数据结构——二叉树

Posted 霜序之晦

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了数据结构——二叉树相关的知识,希望对你有一定的参考价值。

无论是向量、列表、还是栈和队列,其保存的元素之间都存在一个线性次序,故它们都属于线性结构,树则不然,其元素之间并不存在直接后继或直接前驱的关系。不过可以对树附加某种约束,从而确定某种线性次序,因此树属于半线性结构。树有着不计其数的变种,在算法理论以及实际应用中,它们都扮演着最为关键的角色。之所以如此,是因得益于其独特而又普适的逻辑结构。树是一种分层结构,而层次化这一特征几乎蕴含于所有事物及其联系当中,成为其本质属性质疑。从文件系统、互联网域名系统和数据库系统,层次化特征及层次化结构均无处不在。

从图论的角度看,树等价于连通无环图。因此与一般的图相同,树也由一组顶点(vertex),以及联接与其间的若干条边(edge)组成。指定某一特定顶点并称之为根(root),我们也称之为有根树。此时,从程序实现的角度,我们也称顶点为节点(node)。

深度与层次

由树的连通性,每一节点与根节点之间都有一条路径相联;而根据树的无环性,由根通往每个节点的路径必然唯一。因此沿每个节点v到根r的唯一通路所经历的边的数目,称作v的深度(depth),记作depth(v)。依据深度排序,可对所有节点做分层归类。特别地,约定树根节点的深度depth(r) = 0,故属于第0层。

祖先、后代与子树

任一节点在通往树根沿途所经过的每一个节点都是其祖先(ancestor),v是它们的后代(descendant)。特别地,v的祖先/后代包括其本身,而v以外的祖先/后代成为真祖先(proper ancestor)/真后代(proper descendent)。特别地若节点u是v的祖先且恰好比v高一层则称u是v的父亲(parent),v是u的孩子(child)。无孩子的节点称作叶节点(leaf),包含根节点在内的其他节点都称为内部节点(internal node)。v所有的后代及其之间的联边称作子树(subtree),记作subtree(v)。

高度

树T中所有节点深度的最大值称为该树的高度(height),记作height(T)。特别地,仅含单个节点的树的高度为0,空树高度为-1。

多叉树

一般地,树中各节点的孩子数目并不确定。每个节点的孩子数目均不超过k个的有根树,称作k叉树。任何有根有序的多叉树,可以等价地转换为一棵二叉树。

多叉树的“长子”+“兄弟”表示法

有序多叉树中任一非叶节点都有唯一“长子”,而且从该“长子”出发,可以按照预先约定或指定的次序遍历所有孩子节点。

多叉树的“长子”+“兄弟”表示法

 

 

 

 

 

 

尽管二叉树是多叉树的一个子集,但其对应用问题的描述刻画能力绝不低于后者。实际上得益于二叉树的简洁性以及结构的规范性,二叉树所支撑的算法往往能更好地得到描述,更加简洁地得到实现。二叉树的身影几乎出现在所有的应用领域当中,这也是一个重要的原因。

二叉树的实现

作为图的特殊形式,二叉树的基本组成单元是节点与边;作为数据结构,其基本的组成实体是二叉树节点,而边则对应于节点之间的相互引用。

二叉树节点

 1 enum class RBColor
 2 {
 3     //红黑树节点颜色
 4     RED, BlACK
 5 };
 6 
 7 template<typename T>
 8 struct TreeNode
 9 {
10     T _val;                                //保存的值
11     TreeNode<T>* _parent;                //父节点
12     TreeNode<T>* _left;                    //左子节点
13     TreeNode<T>* _right;                //右子节点
14     int _height;                        //树的高度(空树高度为-1)
15     int _npl;                            //null path length  
16     RBColor _color;                        //节点颜色
17     //构造函数
18     TreeNode(T e = T(), TreeNode<T>* parent = nullptr, TreeNode<T>* left = nullptr, TreeNode<T>* right = nullptr,
19         int height = 0, int npl = 1, RBColor color = RBColor::RED)
20         :_val(e), _parent(parent), _left(left), _right(right), _height(height), _npl(npl), _color(color) {}
21     //作为左子节点插入
22     void insertAsLc(T const& e)
23     {
24         assert(!_left);
25         _left = new TreeNode<T>(e, this);
26     }
27     //作为右子节点插入
28     void insertAsRc(T const& e)
29     {
30         assert(!_right);
31         this->_right = new TreeNode<T>(e, this);
32     }
33     //重载比较器、判等器
34     bool operator<(const TreeNode<T>& n)
35     {
36         return _val < n._val;
37     }
38     bool operator>(const TreeNode<T>& n)
39     {
40         return _val > n._val;
41     }
42     bool operator==(const TreeNode<T>& n)
43     {
44         return _val == n._val;
45     }
46     bool operator!=(const TreeNode<T>& n)
47     {
48         return _val != n._val;
49     }
50     //中序遍历下当前节点的直接后继
51     TreeNode<T>* succ();
52 };
53 
54 
55 template<typename T>
56 TreeNode<T>* TreeNode<T>::succ()
57 {
58     TreeNode<T>* s = this;
59     if (_right)
60     {
61         s = _right;
62         while (s->_left)s = s->_left;
63     }
64     else
65     {
66         while (s->_parent && s->_parent->_right == s)s = s->_parent;
67         s = s->_parent;
68     }
69     return s;
70 }

二叉树

  1 template<typename T>
  2 class BinTree
  3 {
  4 protected:
  5     TreeNode<T>* _root;                            //树根节点
  6     size_t _size;                                //树的规模
  7     TreeNode<T>* _clone(TreeNode<T>* Root);        //克隆一棵树
  8     void _setRoot(const T& e);                    //设置树根节点
  9     template<typename F>
 10     void _travPre(TreeNode<T>* root, F&& f);    //先序遍历
 11     template<typename F>
 12     void _travPost(TreeNode<T>* root, F&& f);    //后续遍历
 13     template<typename F>
 14     void _travIn(TreeNode<T>* root, F&& f);        //中序遍历
 15     template<typename F>
 16     void _travLevel(TreeNode<T>* root, F&& f);    //层次遍历
 17     int _remove(TreeNode<T>* rm);                //删除一棵子树
 18     //树的高度
 19     int Height(TreeNode<T>* p) { return p ? p->_height : -1; }
 20     //更新树的高度
 21     int _updateHeight(TreeNode<T>* p);
 22     void _updateHeightAbove(TreeNode<T>* p);
 23     //判断是根节点、叶节点
 24     bool _isLeaf(TreeNode<T>* p);
 25     bool _isRoot(TreeNode<T>* p);
 26 public:
 27     //构造
 28     BinTree() :_root(nullptr), _size(0) {}
 29     //拷贝
 30     BinTree(const BinTree<T>& Tree);
 31     //重载赋值运算符
 32     BinTree<T>& operator=(const BinTree<T>& Tree);
 33     //析构
 34     ~BinTree();
 35     size_t size()const { return _size; }
 36     bool empty()const { return !_size; }
 37     TreeNode<T>* root() { return _root; }
 38     //e作为p的左、右孩子插入
 39     void insertAsLc(TreeNode<T>* p, T const& e)
 40     {
 41         p->insertAsLc(e);
 42         _size++;
 43     }
 44     void insertAsRc(TreeNode<T>* p, T const& e)
 45     {
 46         p->insertAsRc(e);
 47         _size++;
 48     }
 49     //作为根节点插入
 50     void insertAsRoot(const T& e)
 51     {
 52         _setRoot(e);
 53     }
 54     //树的遍历
 55     template<typename F>
 56     void travPre(F&& f)
 57     {
 58         _travPre(_root, f);
 59     }
 60     template<typename F>
 61     void travIn(F&& f)
 62     {
 63         _travIn(_root, f);
 64     }
 65     template<typename F>
 66     void travPost(F&& f)
 67     {
 68         _travPost(_root, f);
 69     }
 70     template<typename F>
 71     void travLevel(F&& f)
 72     {
 73         _travLevel(_root, f);
 74     }
 75     //删除子树
 76     void remove(TreeNode<T>* rm);
 77 };
 78 
 79 template<typename T>
 80 TreeNode<T>* BinTree<T>::_clone(TreeNode<T>* Root)
 81 {
 82     if (Root)
 83     {
 84         TreeNode<T>* root = new TreeNode<T>(*Root);
 85         TreeNode<T>* left = _clone(Root->_left);
 86         TreeNode<T>* right = _clone(Root->_right);
 87         root->_left = left;
 88         root->_right = right;
 89         return root;
 90     }
 91     else
 92         return nullptr;
 93 }
 94 
 95 template<typename T>template<typename F>
 96 void BinTree<T>::_travPre(TreeNode<T>* root, F&& f)
 97 {
 98     Stack<TreeNode<T>*>s;
 99     TreeNode<T>* cur = root;
100     while (1)
101     {
102         while (cur)
103         {
104             f(cur->_val);
105             s.push(cur->_right);
106             cur = cur->_left;
107         }
108         if (s.empty())break;
109         cur = s.top();
110         s.pop();
111     }
112 }
113 
114 
115 template<typename T>template<typename F>
116 void BinTree<T>::_travIn(TreeNode<T>* root, F&& f)
117 {
118     Stack<TreeNode<T>*>s;
119     TreeNode<T>* cur = root;
120     while (1)
121     {
122         if (cur)
123         {
124             s.push(cur);
125             cur = cur->_left;
126         }
127         else if (!s.empty())
128         {
129             cur = s.top();
130             s.pop();
131             f(cur->_val);
132             cur = cur->_right;
133         }
134         else break;
135     }
136 }
137 
138 template<typename T>template<typename F>
139 void BinTree<T>::_travPost(TreeNode<T>* root, F&& f)
140 {
141     if (!root)return;
142     Stack<TreeNode<T>*>s;
143     TreeNode<T>* cur = root;
144     s.push(cur);
145     bool backTrack = false;
146     while (!s.empty())
147     {
148         cur = s.top();
149         if (!backTrack && cur->_right)
150         {
151             s.push(cur->_right);
152             backTrack = false;
153         }
154         if (!backTrack && cur->_left)
155         {
156             s.push(cur->_left);
157             backTrack = false;
158         }
159         if (backTrack || (!cur->_left && !cur->_right))
160         {
161             f(cur->_val);
162             s.pop();
163             backTrack = true;
164         }
165         if (!s.empty() && (s.top()->_left != cur && s.top()->_right != cur))
166             backTrack = false;
167     }
168 }
169 
170 template<typename T>template<typename F>
171 void BinTree<T>::_travLevel(TreeNode<T>* root, F&& f)
172 {
173     Queue<TreeNode<T>*>q;
174     if (root)q.push(root);
175     while (!q.empty())
176     {
177         TreeNode<T>* cur = q.front();
178         f(cur->_val);
179         if (cur->_left)q.push(cur->_left);
180         if (cur->_right)q.push(cur->_right);
181         q.pop();
182     }
183 }
184 
185 
186 template<typename T>
187 int BinTree<T>::_remove(TreeNode<T>* rm)
188 {
189     if (!rm)return 0;
190     int n = 1 + _remove(rm->_left) + _remove(rm->_right);
191     delete rm;
192     return n;
193 }
194 
195 template<typename T>
196 int BinTree<T>::_updateHeight(TreeNode<T>* p)
197 {
198     return p->_height = max(Height(p->_left), Height(p->_right)) + 1;
199 }
200 
201 template<typename T>
202 void BinTree<T>::_updateHeightAbove(TreeNode<T>* p)
203 {
204     while (p)
205     {
206         _updateHeight(p);
207         p = p->_parent;
208     }
209 }
210 
211 template<typename T>
212 bool BinTree<T>::_isRoot(TreeNode<T>* p)
213 {
214     return !p->_parent;
215 }
216 
217 template<typename T>
218 bool BinTree<T>::_isLeaf(TreeNode<T>* p)
219 {
220     return !p->_left && !p->_right;
221 }
222 
223 
224 template<typename T>
225 void BinTree<T>::_setRoot(const T& e)
226 {
227     if (_root)remove(_root);
228     _root = new TreeNode<T>(e);
229     _size = 1;
230 }
231 
232 template<typename T>
233 BinTree<T>::BinTree(const BinTree<T>& Tree) :_size(0), _root(nullptr)
234 {
235     _root = _clone(Tree._root);
236     _size = Tree._size;
237 }
238 
239 template<typename T>
240 BinTree<T>& BinTree<T>::operator=(const BinTree<T>& Tree)
241 {
242     if (this == &Tree)return *this;
243     if (_root)remove(_root);
244     _root = _clone(Tree._root);
245     _size = Tree._size;
246     return *this;
247 }
248 
249 template<typename T>
250 BinTree<T>::~BinTree()
251 {
252     remove(_root);
253 }
254 
255 template<typename T>
256 void BinTree<T>::remove(TreeNode<T>* rm)
257 {
258     if (!rm)return;
259     if (rm->_parent && rm->_parent->_left == rm)rm->_parent->_left = nullptr;
260     else if (rm->_parent && rm->_parent->_right == rm)rm->_parent->_right = nullptr;
261     this->_updateHeightAbove(rm->_parent);
262     int n = _remove(rm);
263     _size -= n;
264 }

子树删除

 1 template<typename T>
 2 int BinTree<T>::_remove(TreeNode<T>* rm)
 3 {
 4     if (!rm)return 0;                    //递归基
 5     //递归删除左右子树
 6     int n = 1 + _remove(rm->_left) + _remove(rm->_right);
 7     //删除当前节点
 8     delete rm;
 9     //返回删除的节点数
10     return n;
11 }
12 
13 template<typename T>
14 void BinTree<T>::remove(TreeNode<T>* rm)
15 {    //删除二叉树节点rm
16     if (!rm)return;
17     //切断来自其父亲节点的引用
18     if (rm->_parent && rm->_parent->_left == rm)rm->_parent->_left = nullptr;
19     else if (rm->_parent && rm->_parent->_right == rm)rm->_parent->_right = nullptr;
20     //因为删除节点,其父亲节点高度可能会变化
21     //更新父亲节点的高度
22     this->_updateHeightAbove(rm->_parent);
23     //记录删除的节点总数
24     int n = _remove(rm);
25     //更新树的规模
26     _size -= n;
27 }

高度更新

二叉树任一节点的高度等于其孩子节点的最大高度加一。因此每当一个节点的孩子或后代有所增减,其高度都有必要及时更新。此处采用另一种策略,即一旦有节点离开或加入二叉树,就更新其所有祖先的高度,这与前述方法等效。

 1 template<typename T>
 2 int BinTree<T>::_updateHeight(TreeNode<T>* p)
 3 {
 4     return p->_height = max(Height(p->_left), Height(p->_right)) + 1;
 5 }
 6 
 7 template<typename T>
 8 void BinTree<T>::_updateHeightAbove(TreeNode<T>* p)
 9 {
10     while (p)
11     {
12         _updateHeight(p);
13         p = p->_parent;
14     }
15 }

先序遍历

先访问节点本身,再分别访问其左右子树。

 1 template<typename T>template<typename F>
 2 void BinTree<T>::_travPre(TreeNode<T>* root, F&& f)
 3 {    //先序遍历递归版本
 4     if (!root)return;
 5     f(root->_val);
 6     _travPre(root->_left, f);
 7     _travPre(root->_right, f);
 8 }
 9 
10 template<typename T>template<typename F>
11 void BinTree<T>::_travPre(TreeNode<T>* root, F&& f)
12 {    //先序遍历迭代版本
13     Stack<TreeNode<T>*>s;            //辅助栈
14     TreeNode<T>* cur = root;        
15     while (1)
16     {
17         while (cur)
18         {
19             f(cur->_val);            //访问当前节点
20             s.push(cur->_right);    //右节点入栈
21             cur = cur->_left;        //沿左侧分支深入一层
22         }                            
23         if (s.empty())break;        //栈空就退出循环
24         cur = s.top();                //下一轮循环
25         s.pop();
26     }
27 }

以先序遍历为例,以上为递归和迭代版本的实现,中序遍历和后序遍历的递归算法与之类似。递归版的实现更加简明,然而其空间、时间复杂度相对于迭代版都更大。

中序遍历

对于后面的二叉搜索树,中序遍历至关重要,相关算法的一项基本操作,就是定位任一节点在中序遍历序列中的直接后继。

 1 template<typename T>
 2 TreeNode<T>* TreeNode<T>::succ()
 3 {
 4     TreeNode<T>* s = this;
 5     //若有右子树,则直接后继必在右子树中
 6     if (_right)
 7     {
 8         s = _right;                //在右子树中
 9         //最靠左(最小)的节点
10     

以上是关于数据结构——二叉树的主要内容,如果未能解决你的问题,请参考以下文章

数据结构中二叉树的顺序存储结构代码怎么编写?

数据结构二叉树经典基础习题

数据结构 二叉树的简单理解和代码实现

求数据结构算法平衡二叉树实现代码

输出二叉树树形的数据结构程序代码怎么写

求数据结构(C语言版)建立二叉树的代码~~急~~谢谢了