数据结构学习笔记04树(二叉树二叉搜索树平衡二叉树)

Posted kuotian

tags:

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

一.树

树的基本术语

  ①结点的度(Degree):结点的子树个数

  ②树的度:树的所有结点中最大的度数

  ③叶结点(Leaf):度为0的结点

  ④父结点(Parent):有子树的结点是其子树的根结点的父结点

  ⑤子结点(Child):若A结点是B结点的父结点,则称B结点是A结点的子结点;子结点也称孩子结点。

  ⑥兄弟结点(Sibling):具有同一父结点的各结点彼此是兄弟结点。

  ⑦路径和路径长度:从结点n1到nk的路径为一个结点序列n1 , n2 ,… , nk , ni是 ni+1的父结点。路径所包含边的个数为路径的长度。

  ⑧ 祖先结点(Ancestor):沿树根到某一结点路径上的所有结点都是这个结点的祖先结点。

  ⑨子孙结点(Descendant):某一结点的子树中的所有结点是这个结点的子孙。

    ⑩结点的层次(Level):规定根结点在1层,其它任一结点的层数是其父结点的层数加1。 12. 树的深度(Depth):树中所有结点中的最大层次是这棵树的深度。

 

二.二叉树

 

二叉树的性质

 

  ①一个二叉树第 i 层的最大结点数为:2^(i-1) (i>=1)

 

  ②深度为k的二叉树至多有2^k-1个结点 (i>=1)

 

  ③对任何非空二叉树 T,若n0表示叶结点的个数、n2是度为2的非叶结点个数,那么两者满足关系n0 = n2 +1    ---> n0+n1+n2 = B + 1 = n0 * 0 + n1 * 1 + n2 * 2 + 1

1.顺序存储结构

 

完全二叉树:按从上至下、从左到右顺序存储

N个结点的完全二叉树的结点父子关系:

  ①    非根结点(序号i > 1)的父结点的序号[ i / 2]

  ②    结点(序号为i) 的左孩子结点序号 2i,(若2i <=n,否则无左孩子)

  ③    结点(序号为i) 的左孩子结点序号 2i +1,(若2i + 1<=n,否则无右孩子)

非完全二叉树 ---> 补全为完全二叉树

 

2.链式存储结构(代码:sj4_0)

  1 //二叉树
  2 #include <iostream>
  3 #include <cstdio>
  4 #include <stdlib.h>
  5 #include <stack>
  6 #include <queue>
  7 using namespace std;
  8 #define OK 1
  9 #define ERROR 0
 10 #define OVERFLOW -1
 11 
 12 typedef int Status;/* Status是函数的类型,其值是函数结果状态代码,如OK等 */
 13 typedef int TElemType;/* ElemType类型根据实际情况而定,这里假设为int*/
 14 
 15 typedef struct BinTNode *BinTree;
 16 struct BinTNode
 17 {
 18     TElemType data;
 19     BinTree left;
 20     BinTree right;
 21 }; 
 22 
 23 Status CreatBiTree(BinTree &T);
 24 Status PreOrderTraverse(BinTree T);
 25 Status InOderTraverse(BinTree T);
 26 Status PostOrderTraverse(BinTree T);
 27 
 28 Status StackPreOrderTraverse(BinTree T);
 29 Status StackInOrderTraverse(BinTree T);
 30 Status StackPostOrderTraverse(BinTree T);
 31 
 32 Status LevelOrderTraverse(BinTree T);
 33 
 34 int PostOrderGetHeight(BinTree T);
 35 
 36 Status InitBiTree(BinTree &T);
 37 Status DestroyBiTree(BinTree &T);
 38 Status ClearBiTree(BinTree &T);
 39 bool BiTreeEmpty(BinTree T);
 40 TElemType Root(BinTree T);
 41 TElemType Value(BinTree p);
 42 void Assign(BinTree p,TElemType value);
 43  
 44 /*按先序次序输入二叉树中的结点值,负数表示空树 
 45 构造二叉链表表示的二叉树*/
 46 Status CreatBiTree(BinTree &T)        
 47 {
 48     TElemType data;
 49     scanf("%d",&data);
 50     if(data < 0 ) 
 51         T = NULL;
 52     else {
 53         if( !(T = (BinTree)malloc(sizeof(BinTNode))) )
 54             exit(OVERFLOW); 
 55         T->data = data;
 56         CreatBiTree(T->left);
 57         CreatBiTree(T->right);
 58     }
 59     return OK;
 60 }
 61 
 62 //递归实现先序遍历 
 63 Status PreOrderTraverse(BinTree T)
 64 {
 65     if(T) {
 66         printf("%5d", T->data);
 67         PreOrderTraverse(T->left);
 68         PreOrderTraverse(T->right);
 69     }
 70     return OK;
 71 }
 72 //递归实现中序遍历 
 73 Status InOderTraverse(BinTree T)
 74 {
 75     if(T) {
 76         PreOrderTraverse(T->left);
 77         printf("%5d", T->data);
 78         PreOrderTraverse(T->right);
 79     }
 80     return OK;
 81 }
 82 //递归实现后序遍历  
 83 Status PostOrderTraverse(BinTree T)
 84 {
 85     if(T) {
 86         PreOrderTraverse(T->left);
 87         PreOrderTraverse(T->right);
 88         printf("%5d", T->data);
 89     }
 90     return OK;
 91 }
 92 
 93 //非递归实现先序遍历:堆栈 
 94 Status StackPreOrderTraverse(BinTree T)
 95 {
 96     if(T == NULL)
 97         return ERROR;  
 98     BinTree BT = T;
 99     stack<BinTree> stack;
100     while(BT || !stack.empty() ) {
101         while(BT) {            //一直向左将沿途结点压入堆栈 
102             printf("%5d",BT->data);    //访问打印结点 
103             stack.push(BT);
104             BT = BT->left;
105         }
106         if( !stack.empty() ) {    
107             BT = stack.top();        //记录弹出结点 
108             stack.pop();
109             BT = BT->right;         //转向右子树 
110         }
111     }
112     return OK;    
113 }
114 
115 //非递归实现中序遍历:堆栈 
116 Status StackInOrderTraverse(BinTree T)
117 {
118     if(T == NULL)
119         return ERROR;  
120     BinTree BT = T;
121     stack<BinTree> stack;
122     while(BT || !stack.empty() ) {
123         while(BT) {            //一直向左将沿途结点压入堆栈 
124             stack.push(BT);
125             BT = BT->left;
126         }
127         if( !stack.empty() ) {        //////
128             BT = stack.top();        //记录弹出结点 
129             stack.pop();
130             printf("%5d",BT->data);    //访问打印结点 
131             BT = BT->right;         //转向右子树 
132         }
133     }
134     return OK;    
135 }
136 
137 //非递归实现后序遍历:堆栈 
138 /*后序遍历LRG:第一遍入栈,G再第二遍被遍历到时,若有右孩子,则入栈(等待第三次遍历);
139 如无右孩子,或右孩子已被访问,则访问G结点。*/ 
140 Status StackPostOrderTraverse(BinTree T)
141 {
142     if(T == NULL)
143         return ERROR;  
144     BinTree BT = T;
145     stack<BinTree> stack;
146     BinTree lastNode = NULL, currentNode = NULL;//lastNode记录被访问过的前一个结点 
147     while( BT || !stack.empty() ) {
148         while(BT) {                //一直向左将沿途结点压入堆栈 
149             stack.push(BT);
150             BT = BT->left;
151         }
152         while( !stack.empty() ) {
153             currentNode = stack.top();    //当前节点
154             stack.pop();                //出栈
155             if( currentNode->right == NULL || currentNode->right == lastNode) {//无右子树或右子树已被访问     
156                 printf("%5d",currentNode->data);
157                 lastNode = currentNode;
158             }else {        //右子树未被访问过 
159                 stack.push(currentNode);
160                 currentNode = currentNode->right;
161                 while(currentNode) {
162                     stack.push(currentNode);
163                     currentNode = currentNode->left;
164                 }
165             }
166         }
167     }
168     return OK;
169 }
170 
171 //层序遍历:队列 
172 Status LevelOrderTraverse(BinTree T)
173 {
174     if(T == NULL)
175         return ERROR;
176     BinTree BT = T;
177     queue<BinTree> queue;
178     queue.push(BT);
179     while( !queue.empty() ) {
180         BinTree temp = queue.front();
181         printf("%5d", temp->data);
182         queue.pop();
183         if(temp->left)
184             queue.push(temp->left);
185         if(temp->right)
186             queue.push(temp->right);
187     }
188     printf("\\n");
189     return OK;
190 }
191 
192 //后序遍历求树深度(高) 
193 int PostOrderGetHeight(BinTree T)
194 {
195     int leftHeight, rightHeight, maxHeight;
196     if(T) {
197         leftHeight = PostOrderGetHeight(T->left);    //左子树深度 
198         rightHeight = PostOrderGetHeight(T->right);    //右子树深度 
199         maxHeight = leftHeight > rightHeight ? leftHeight : rightHeight;
200         return (maxHeight+1);    //返回树的深度 
201     }
202     else 
203         return 0;//空树深度为0 
204 } 
205  
206 //构造空二叉树T 
207 Status InitBiTree(BinTree &T)
208 {
209     T = NULL;
210     return OK;
211 }
212 //销毁二叉树T 
213 Status DestroyBiTree(BinTree &T)
214 {
215     if(T) {
216         if(T->left)
217             DestroyBiTree(T->left);
218         if(T->right)
219             DestroyBiTree(T->right);
220         free(T);    //释放该结点 
221         T = NULL;    //T置空 
222     }
223     return OK;
224 }
225 /*清空二叉树T 
226 清空和销毁有什么区别么*/ 
227 Status ClearBiTree(BinTree &T)
228 {
229     if(T) {
230         if(T->left)
231             DestroyBiTree(T->left);
232         if(T->right)
233             DestroyBiTree(T->right);
234         free(T);    //释放该结点 
235         T = NULL;    //T置空 
236     }
237     return OK;
238 } 
239 
240 bool BiTreeEmpty(BinTree T)
241 {
242     if( !T )
243         return true;
244     else
245         return false;
246 }
247 
248 //返回T的根
249 TElemType Root(BinTree T)
250 { 
251     if(BiTreeEmpty(T))
252         return -1;
253     else
254         return T->data;
255 }
256 
257 //返回p所指结点的值 
258 TElemType Value(BinTree p)
259 {
260     return p->data;
261 }
262 
263 // 给p所指结点赋值为value 
264 void Assign(BinTree p,TElemType value)
265 {
266     p->data=value;
267 }
268 
269 
270 
271 int main()
272 {
273     BinTree T;
274     CreatBiTree(T);
275     printf("先序递归遍历:  "); 
276     PreOrderTraverse(T);
277     printf("\\n先序非递归遍历:"); 
278     StackPreOrderTraverse(T);
279     
280     printf("\\n中序递归遍历:  "); 
281     InOderTraverse(T);
282     printf("\\n中序非递归遍历:"); 
283     StackInOrderTraverse(T);
284     
285     printf("\\n后序递归遍历:  "); 
286     PostOrderTraverse(T);
287     printf("\\n后序非递归遍历:"); 
288     StackPostOrderTraverse(T);
289     
290     printf("\\n层序遍历:      "); 
291     LevelOrderTraverse(T);
292     printf("\\n树的高度:%d\\n",PostOrderGetHeight(T)); 
293     if(BiTreeEmpty(T))
294         printf("空\\n");
295     else
296         printf("不空\\n");
297     printf("树的根:%d\\n",Root(T)); 
298     
299         
300 
301     return 0;
302 }
sj4_0

先序GLR:第一次遇到该结点则输出。

中序LGR:第二次遇到该结点则输出。

后序LRG:第三次遇到该结点则输出。

typedef struct BinTNode *BinTree;

struct BinTNode

{

       TElemType data;

       BinTree left;

       BinTree right;

};

先序递归算法

 1 //递归实现先序遍历 
 2 Status PreOrderTraverse(BinTree T)
 3 {
 4     if(T) {
 5         printf("%5d", T->data);
 6         PreOrderTraverse(T->left);
 7         PreOrderTraverse(T->right);
 8     }
 9     return OK;
10 }
View Code

先序遍历非递归遍历算法

  ①遇到一个结点,访问打印它,将其压栈,并遍历它的左子树

  ②当左子树遍历结束后,从栈顶弹出这个结点

  ③然后按其右指针再去先序遍历该结点的右子树

 1 Status StackPreOrderTraverse(BinTree T)
 2 {
 3     if(T == NULL)
 4         return ERROR;  
 5     BinTree BT = T;
 6     stack<BinTree> stack;
 7     while(BT || !stack.empty() ) {
 8         while(BT) {            //一直向左将沿途结点压入堆栈 
 9             printf("%5d",BT->data);    //访问打印结点 
10             stack.push(BT);
11             BT = BT->left;
12         }
13         if( !stack.empty() ) {    
14             BT = stack.top();        //记录弹出结点 
15             stack.pop();
16             BT = BT->right;         //转向右子树 
17         }
18     }
19     return OK;    
20 }
View Code

中序遍历非递归遍历算法

  ①遇到一个结点,就把它压栈,并遍历它的左子树

  ②当左子树遍历结束后,从栈顶弹出这个结点并访问它

  ③然后按其右指针再去中序遍历该结点的右子树

 1 //非递归实现中序遍历:堆栈 
 2 Status StackInOrderTraverse(BinTree T)
 3 {
 4     if(T == NULL)
 5         return ERROR;  
 6     BinTree BT = T;
 7     stack<BinTree> stack;
 8     while(BT || !stack.empty() ) {
 9         while(BT) {            //一直向左将沿途结点压入堆栈 
10             stack.push(BT);
11             BT = BT->left;
12         }
13         if( !stack.empty() ) {        //////
14             BT = stack.top();        //记录弹出结点 
15             stack.pop();
16             printf("%5d",BT->data);    //访问打印结点 
17             BT = BT->right;         //转向右子树 
18         }
19     }
20     return OK;    
21 }
View Code

后序遍历非递归算法

  后序遍历LRG:第一遍入栈,G再第二遍被遍历到时,若有右孩子,则入栈(等待第三次遍历);如无右孩子,或右孩子已被访问,则访问G结点。

 1 //非递归实现后序遍历:堆栈 
 2 Status StackPostOrderTraverse(BinTree T)
 3 {
 4     if(T == NULL)
 5         return ERROR;  
 6     BinTree BT = T;
 7     stack<BinTree> stack;
 8     BinTree lastNode = NULL, currentNode = NULL;//lastNode记录被访问过的前一个结点 
 9     while( BT || !stack.empty() ) {
10         while(BT) {                //一直向左将沿途结点压入堆栈 
11             stack.push(BT);
12             BT = BT->left;
13         }
14         while( !stack.empty() ) {
15             currentNode = stack.top();    //当前节点
16             stack.pop();                //出栈
17             if( currentNode->right == NULL || currentNode->right == lastNode) {//无右子树或右子树已被访问     
18                 printf("%5d",currentNode->data);
19                 lastNode = currentNode;
20             }else {        //右子树未被访问过 
21                 stack.push(currentNode);
22                 currentNode = currentNode->right;
23                 while(currentNode) {
24                     stack.push(currentNode);
25                     currentNode = currentNode->left;
26                 }
27             }
28         }
29     }
30     return OK;
31 }
View Code

层序遍历算法:先根结点入队,然后

  ①从队列取出一个元素

  ②访问打印该元素所指结点

  ③若该元素有左右孩子,则左右孩子顺序入队