二叉树的存储表示

news/2025/2/12 7:47:31/

二叉树的数组存储表示

在数据处理过程中二叉树的大小、形态不发生剧烈的动态变化的场合,适宜采用数组方式来表示二叉树的抽象数据类型
1、完全二叉树的数组存储表示
设有一棵完全二叉树,将其所有结点按照层次自顶向下、同一层自左向右进行按序编号1 - n,得到一个结点的顺序(线性)序列。在数组下标为 i 的位置,存放编号为 i 的完全二叉树的结点。这种存储表示是存储完全二叉树最简单、最省存储的方式,因为可以从一个结点的编号推算出它的父结点、子女、兄弟等结点的编号

数组存储的缺陷:对待一般二叉树来说,有可能导致浪费大量存储空间。

二叉树的链表存储表示

使用链式存储,可以在形态剧烈变化的二叉树中,克服数组存储的缺点

1、根据二叉树的定义,每一个结点都有两个分支,指向左、右子树。所以二叉树的结点至少包括三个域:数组data、左子女指针left、右子女指针right。其称为二叉链表,可以很方便地找到左右子结点,但是找到其父结点很困难。

2、在含有n个结点的二叉链表中有n+1个空链指针域,因为在所有结点的2n个链指针域只有n-1个存有边信息的缘故。

三叉链表

在二叉链表的基础上,增加指向parent的指针,便于查找任意结点的父结点。三链表则有n+2个空链指针域。

二叉树结点定义

template<class T>
struct BinTreeNode{T data;BinTreeNode<T> *leftChild, *rightChild;BinTreeNode(): leftChild(nullptr), rightChild(nullptr){}BinTreeNode(T x, BinTreeNode<T> *l = nullptr, BinTreeNode<T> *r = nullptr):data(x), leftChild(l), rightChild(r){}
};

二叉树类定义

template<class T>
class BinaryTree{
public:BinaryTree(): root(nullptr){}               //构造函数BinaryTree(T value): RefValue(value), root(nullptr){}         //构造函数BinaryTree(BinaryTree<T>& s);          //复制构造函数~Binary(){ destroy(root); } 				//析构函数bool IsEmpty(){ return (root == nullptr) ? true : false; }             //判断二叉树空否BinTreeNode<T>* Parent(BinTreeNode<T> *current)                       //返回父结点{return (root == NULL || root == current)?NULL:Parent(root, current); }BinTreeNode<T>* LeftChild(BinTreeNode<T> *current)                    //返回左子女{return (current != NULL)?current->leftChild:NULL; }BinTreeNode<T>* RightChild(BinTreeNode<T> *current)					  //返回右子女{return (current != NULL)?current->rightChild:NULL; }int Height() { return Height(root); }                                 //返回树高度int Size() {return Size(root); }                                      //返回结点数BinTreeNode<T>* getRoot() const {return root; }                       //取根void preOrder(void (*visit)(BinTreeNode<T>* p))                       //前序遍历{preOrder(root, visit); }void inOrder(void (*visit)(BinTreeNode<T>* p))                        //中序遍历{inOrder(root, visit); }void postOrder(void (*visit)(BinTreeNode<T>* p))                      //后序遍历{postOrder(root, visit); }int Insert(const T& item);                                            //插入新元素BinTreeNode<T>* Find(T& item)const;                                   //搜索
protected:BinTreeNode<T>* root;                                                 //二叉树的根指针T RefValue;                  										  //数据输入停止标志void CreateBinTree(istream& in, BinTreeNode<T>* &subTree);            //从文件读入建树bool Insert(BinTreeNode<T>* &subTree, const T& x);                    //插入void destroy(BinTreeNode<T>* &subTree);								  //删除                      bool Find(BinTreeNode<T>* subTree, const T& x)const;                  //查找BinTreeNode<T>* Copy(BinTreeNode<T>* orignode);                       //复制int Height(BinTreeNode<T>* subTree);								  //返回树高度int Size(BinTreeNode<T> *sunTree);                                    //返回结点数BinTreeNode<T>* Parent(BinTreeNode<T>* subTree, BinTreeNode<T>* current);      //返回父结点BinTreeNode<T>* Find(BinTreeNode<T>* subTree, const T& x)const;         //搜寻xvoid Traverse(BinTreeNode<T>* subTree, ostream& out);                 //前序遍历输出void preOrder(BinTreeNode<T>* subTree, void (*visit)(BinTreeNode<T>* p))               //前序遍历void inOrder(BinTreeNode<T>* subTree, void (*visit)(BinTreeNode<T>* p))                //中序遍历void postOrder(BinTreeNode<T>* subTree, void (*visit)(BinTreeNode<T>* p))              //后序遍历friend istream& operator>>(istream& in, BinaryTree<T>& Tree);			//重载输入操作符friend ostream& operator<<(ostream& out, BinaryTree<T>& Tree);			//重载输出操作符
};

部分成员函数实现

//删除根为subTree的子树
template<class T>
void BinaryTree<T>::destroy(BinTreeNode<T>* &subTree){if(subTree != nullptr){destroy(subTree->leftChild);destroy(subTree->rightChild);delete subTree;}
};//搜索current结点的父结点
template<class T>
BinTreeNode<T>* BinaryTree<T>::Parent(BinTreeNode<T>* subTree, BinTreeNode<T>* current){if(subTree == nullptr){return nullptr;}if(subTree -> leftChild == current || subTree -> rightChild == current){return subTree;}BinTreeNode<T> *p;if((p = Parent(subTree->leftChild, current)) != nullptr) return p;else return Parent(subTree->rightChild, current);
};//搜索并输入根为subTree的二叉树
template<class T>
void BinaryTree<T>::Traverse(BinTreeNode<T> *subTree, ostream& out){if(subTree != nullptr){out << subTree -> data << ' ';            //输出当前结点的数据Traverse(subTree->leftChild, out);	      //输出Traverse(subTree->rightChild, out);}
};//重载输入操作符
template<class T>
istream& operator>>(istream& in, BinaryTree<T>& Tree){CreateBinTree(in, Tree.root);                     //采用广义表表示的建立二叉树的算法return in;
}//重载输出操作符
template<class T>
ostream& operator<<(ostream& out, BinaryTree<T>& Tree){out << "输出二叉树的前序遍历\n";Tree.Traverse(Tree.root, out);out << endl;return out;
}

一种采用广义表表示的建立二叉树的算法

假定有一广义表 A(B(D,E(G,)),C(,F))#
算法基本思路:依次从保存广义表的字符串中输入字符。
1、以字母作为结点的值,k=1时为左子女,k=2时为右子女。
2、遇到左括号,表示子表开始;遇到右括号,表示子表结束。
3、遇到逗号,则表示左子女处理完毕,接着处理右子女,k置为2,直到#。在进入子表之前将根结点入栈,子表处理结束之后退栈。

template<class T>
void BinaryTree<T>::CreateBinTree(istream& in, BinTreeNode<T>* &subTree){stack<BinTreeNode<T>*> s;               //存放根结点的栈subTree = nullptr;						//置空二叉树BinTreeNode<T> *p, *t;int k;									//作为处理左、右子树标记T ch;in >> ch;        						//从in顺序读入一个字符while (ch != RefValue) {switch (ch) {case '(': s.push(p); k = 1; break;			//进入子树case ')': s.pop(); break;					//退出子树case ',': k = 2; break;						//处理右子树default: p = new BinTreeNode<T>(ch);	if (subTree == nullptr) subTree = p;else if (k == 1) {t = s.top();t->leftChild = p;					//链接左子女}else {t = s.top();t->rightChild = p;					//链接右子女}}in >> ch;}
}

http://www.ppmy.cn/news/744361.html

相关文章

Android 点击View实现翻转动画仿金立软件商店会员点击翻转

代码如下 直接使用工具类: import android.animation.Animator; import android.animation.ObjectAnimator; import android.view.View; import android.view.animation.OvershootInterpolator; public class AnimUtil { public static void FlipAnimatorXViewShow(final…

不仅仅是商务旗舰,金立M2017的拍照实力同样给力

近年来金立在商务手机市场不断发力&#xff0c;连续推出了多款专为高端商务人士打造的精品商务手机&#xff0c;其中在去年年底发布商务旗舰金立M2017更是获得了大量高端商务人士的认可。但是值得一提的是该机不仅在商务功能方面做得极为出色&#xff0c;就是在拍照方面金立M20…

22. 查询相同时刻多地登陆的用户

文章目录 题目需求思路一实现一题目来源 题目需求 从登录明细表&#xff08;user_login_detail&#xff09;中查询在相同时刻&#xff0c;多地登陆&#xff08;ip_address不同&#xff09;的用户。 期望结果如下&#xff1a; user_id(用户id)101102104… 需要用到的表&…

Docker学习笔记17

跨主机容器间网络&#xff1a; 实现跨主机容器间通信的工具&#xff1a; 1&#xff09;Pipework 2&#xff09;Flannel 3&#xff09;Weave 4&#xff09;Open V Switch &#xff08;OVS&#xff09; 5&#xff09;Calico 1. Weave&#xff1a; 在每个宿主机上布置一个特…

获取今天日期或今天之前多少天 之后多少天

GetDateStr(AddDayCount) {let dd new Date();dd.setDate(dd.getDate() AddDayCount); //获取AddDayCount天后的日期let y dd.getFullYear();let m dd.getMonth() 1 < 10 ? "0" (dd.getMonth() 1) : dd.getMonth() 1; //获取当前月份的日期&#xff0c;不…

2022中元节前后几天不出门?前三天后三天不能出门是真的吗?

随着中元节的临近&#xff0c;在民间所流传的一些习俗也受到大家的关注&#xff0c;部分地区在中元节前后几天有不出门的说法&#xff0c;那中元节前后几天不出门&#xff1f;前三天后三天不能出门是真的吗&#xff1f; 一、2022中元节前后几天不出门&#xff1f; 中元节前3天…

判断第几天

题目描述 输入某年某月某日&#xff0c;判断这一天是这一年的第几天&#xff1f; 输入 输入为一行输入格式为YYYY-MM-DD 输出 输出这天是这一年的第几天 样例输入 2007-01-01 样例输出 1 #include<stdio.h> #include<math.h>int main(){int year,month…

计算该日在本年中是第几天?

定义一个结构体变量&#xff08;包括年、月、日&#xff09;。计算该日在本年中是第几天&#xff1f;注意闰年问题。 输出格式要求&#xff1a;"\n%d月%d日是%d年的第%d天。" 程序的运行示例如下&#xff1a; 请输入日期&#xff08;年&#xff0c;月&#xff0c;日&…