树
树的基本术语
d72517fa6b39dc28ff37c0942cda4df1
结点的度和树的度
树中结点的最大度数称为树的度。如结点B的度为2,结点D的度为3,树的度为3。
孩子,双亲,兄弟结点
路径和路径长度
树中两个结点之间的路径是由这两个结点之间所经过的结点序列构成的,而路径长度是路径上所经过的边的个数。
注意:由于树中的分支是有向的,即从双亲指向孩子,所以树中的路径是从上向下的,同一双亲的两个孩子之间不存在路径。
子孙结点和祖先结点
根A到结点K的唯一路径上的任意结点,称为结点K的祖先。如结点B是结点K的祖先,而结点K是结点B的子孙。
结点的层次和树的高度
结点的层次从树根开始定义,根结点为第1层,它的子结点为第2层,以此类推。
有序树和无序树
树中结点的各子树从左到右是有次序的,不能互换,称该树为有序树,否则称为无序树。
森林
森林是m (m≥0)棵互不相交的树的集合。
树的存储结构
多叉链表表示法
fasdfa
采用多叉链表表示法存储树,许多算法设计可以直接参照二叉树的二叉链表结构的算法。其优点是简单易学,缺点是存在许多指针域的浪费。设树中结点数是n,树的度是k,则共使用了n×k个指针域,而这其中只有n
-1个非空指针城。
孩子链表表示法
safsafsxcx
当树的度较大时,CTree类可以减少多叉链表表示法的空间浪费。但是,当插入、删除结点时,却会涉及多个孩子链表的调整,还有可能造成存储空间的再分配,因此时间复杂度较大。在CTree类中,利用孩子链表可以方便、快捷地查找指定结点的孩子结点。但是,查找双亲结点则需遍历所有的孩子链表,因此效率就低得多了。
双亲表示法
sadfas
在PTree类中,不仅利用结点的双亲指针域很容易找到其双亲结点,而且查找其所有祖先结点也非常便利、高效。若需要查找指定结点的孩子或子孙结点,则需遍历整个树的存储空间,效率就低得多了。
孩子兄弟表示法
dasfgae
因为孩子兄弟表示法建立起了树和二叉树之间的对应关系,所以常常将其称为树的二叉树表示法。相比树的其他存储结构,孩子兄弟表示法既简化了结构,又可以将许多二叉树的优秀算法移植到树结构的应用中来,因此具有很好的学习、应用价值。
树的操作算法
构造算法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42
| CSTree(vector<pair<T, T>>& ps) { if (ps.empty()) { root = nullptr; return; } root = new CSNode<T>(ps[0].first); root->firstchild = nullptr; root->nextsibling = nullptr;
for (size_t i = 0; i < ps.size(); i++) { InsertNode(ps[i]); } }
void InsertNode(pair<T, T>& p) { CSNode<T>* child = new CSNode<T>(p.second); child->firstchild = nullptr; child->nextsibling = nullptr;
CSNode<T>* parent = Search(root, p.first); if (!parent) { cout << "Parent node " << p.first << " not found!" << endl; return; }
if (parent->firstchild == nullptr) { parent->firstchild = child; } else { CSNode<T>* temp = parent->firstchild; while (temp->nextsibling != nullptr) { temp = temp->nextsibling; } temp->nextsibling = child; } }
|
计算树的高度
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| template <class T> int CSTree<T>::Height(CSNode<T>* p) { if (p == nullptr) return 0;
int maxheight = 0;
for (CSNode<T>* child = p->firstchild; child != nullptr; child = child->nextsibling) { int height = Height(child); if (height > maxheight) maxheight = height; }
return maxheight + 1; }
template <class T> int CSTree<T>::Height() { return Height(root); }
|
计算所有结点的度
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| template <class T> void CSTree<T>::Degree(CSNode<T>* p) { if (p == nullptr) return;
p->degree = 0;
for (CSNode<T>* child = p->firstchild; child != nullptr; child = child->nextsibling) { p->degree++; }
Degree(p->firstchild); Degree(p->nextsibling); }
template <class T> void CSTree<T>::Degree() { Degree(root); }
|
二叉树
特殊的二叉树
3ca44306b6c5f97c3544f5d091be9ac4
a99ebdd407f8c2508597d85c610c44a7
二叉树的性质
非空二叉树上的叶子结点数等于度为2的结点数加1,即 n0 = n1 + 1
因为二叉树中所有节点的度只能是 0、1、2,所以节点总数 n = n0 + n1 + n2
其次考虑二叉树的分支总数。将二叉树的分支总数记作 m。
因为所有的分支是由度为 1 和度为 2 的节点发出的,所以m = n1 + 2 × n2
最后,由树的性质 1,可得 n = m + 1,即n0 + n1 + n2 = n1 + 2 × n2 + 1
二叉树的存储结构
顺序结构
afdfa
当二叉树单分支节点较多,高度变化较大时,空间浪费现象惊人
链式结构
adsfgad
二叉树的遍历
前序遍历:根左右
中序遍历:左根右
后序遍历:左右根
先序遍历算法如下
1 2 3 4 5 6 7 8 9 10 11 12 13
| template <class T> void BiTree<T>::PreOrder(BiNode<T>* p) { if (p == NULL) return; cout << p->data; PreOrder(p->lchild); PreOrder(p->rchild); }
template <class T> void BiTree<T>::PreOrder() { PreOrder(root); }
|
层序遍历:利用队列
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| template <class T> void BiTree<T>::LevelOrder() { if (root == NULL) return;
LinkQueue<BiNode<T>*> Q; Q.EnQueue(root);
while (!Q.Empty()) { BiNode<T>* p = Q.DeQueue(); cout << p->data;
if (p->lchild != NULL) Q.EnQueue(p->lchild);
if (p->rchild != NULL) Q.EnQueue(p->rchild); } }
|
二叉树的构造算法
sADF
先序序列是abdecf,带空指针标记的先序序列是abd**e**cf ***
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| template <class T> BinNode<T>* BinTree<T>::CreateByPre(vector<T>& pre, int& i) { T e = pre[i]; i++; if (e == '*') return NULL;
BinNode<T>* p = new BinNode<T>; p->data = e; p->lchild = CreateByPre(pre, i); p->rchild = CreateByPre(pre, i);
return p; }
template <class T> BinTree<T>::BinTree(vector<T>& pre) { int i = 0; root = CreateByPre(pre, i); }
|
二叉树的其他操作算法
计算结点数
1 2 3 4 5 6 7 8 9 10 11 12 13
| template <class T> int BiTree<T>::Count(BiNode<T>* p) { if (p == NULL) return 0; int left = Count(p->lchild); int right = Count(p->rchild); return 1 + left + right; }
template <class T> int BiTree<T>::Count() { return Count(root); }
|
计算高度
1 2 3 4 5 6 7 8 9 10 11 12 13
| template <class T> int BiTree<T>::Height(BiNode<T>* p) { if (p == NULL) return 0; int left = Height(p->lchild); int right = Height(p->rchild); return (left > right ? left : right) + 1; }
template <class T> int BiTree<T>::Height() { return Height(root); }
|
查找结点
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| template <class T> BinNode<T>* BiTree<T>::Search(BinNode<T>* p, T e) { if (p == NULL) return NULL; if (p->data == e) return p;
BinNode<T>* q = Search(p->lchild, e); if (q != NULL) return q;
return Search(p->rchild, e); }
template <class T> BinNode<T>* BiTree<T>::Search(T e) { return Search(root, e); }
|
线索二叉树
asfafs
哈夫曼树
wqqwr
qetqt
参考文献
数据结构:树(Tree)【详解】_数据结构
树-CSDN博客