基于C语言实现二叉树

树是一种数据结构,是由n (n>=1)个有限点组成一个具有层次关系的集合

而二叉树是每个结点最多有两个子树的树结构
下面是关于二叉树的一些简单操作

在之前写过的链表中,是用链表的头节点的指针来表示一个链表,那么在二叉树中,同样是使用根节点的指针来表示一个二叉树
  4 typedef struct TreeNode
  5 {
  6     TreeNodeType data;
  7     struct TreeNode* lchild;
  8     struct TreeNode* rchild;
  9 }TreeNode;
 10 

1.二叉树的初始化
  8 void TreeInit(TreeNode** pRoot)
  9 {
 10     if(pRoot == NULL)
 11     {
 12         //非法输入
 13         return ;
 14     }
 15     *pRoot = NULL;
 16     return;
 17 }

2.二叉树的先序、中序、后续、层序
(1)二叉树的先序

二叉树的先序的顺序为先遍历树的根节点,再遍历根节点的左子树,最后再遍历根节点的右子树
上面这张图的先序遍历结果为ABDEGCF

下面是使用递归的方法来遍历地得出二叉树的先序遍历,首先先访问根节点(即打印根节点),再分别遍历左右子树

 34 //先序遍历树
 35 void TreePreOrder(TreeNode* root)
 36 {
 37     if(root == NULL)
 38     {
 39         //空树
 40         return ;
 41     }
 42     //先访问根节点
 43     printf("%c",root->data);
 44     //遍历左子树
 45     TreePreOrder(root->lchild);
 46     //遍历右子树
 47     TreePreOrder(root->rchild);
 48     return ;
 49 }

(2)二叉树的中序
二叉树的中序遍历顺序为先遍历二叉树的左子树,再遍历二叉树的根节点,最后再遍历右子树
上面这张图的中序遍历结果为DBGEACF
下面是使用递归的方法来遍历地得出二叉树的中序遍历,首先先遍历左子树,再访问根节点(即打印根节点),最后再遍历右子树
 51 //中序遍历树
 52 void TreeInOrder(TreeNode* root)
 53 {
 54     if(root == NULL)
 55     {
 56         //空树
 57         return ;
 58     }
 59     //遍历左子树
 60     TreeInOrder(root->lchild); 
 61     //先访问根节点
 62     printf("%c",root->data);
 63     //遍历右子树
 64     TreeInOrder(root->rchild);
 65     return ;                                                                                                
 66 }
(3)二叉树的后序

二叉树的后序遍历顺序为先遍历二叉树的左子树,再遍历二叉树的右子树,最后再遍历二叉树的根节点
上面这张图的后序遍历结果为DGEBFCA
下面是使用递归的方法来遍历地得出二叉树的后序遍历,首先先遍历左子树,再遍历右子树,最后再访问根节点(即打印根节点)
 69 //后序遍历树
 70 void TreePostOrder(TreeNode* root)
 71 {
 72     if(root == NULL)
 73     {
 74         //空树
 75         return ;
 76     }
 77     //遍历左子树
 78     TreePostOrder(root->lchild); 
 79     //遍历右子树
 80     TreePostOrder(root->rchild);
 81     //先访问根节点
 82     printf("%c",root->data);                                                                                
 83     return ;
 84 }

扫描二维码关注公众号,回复: 699385 查看本文章
(4)二叉树的层序
二叉树的层序就是按照二叉树的层来进行打印
下面是通过使用一个数组来实现这个操作,首先先创建一个数组,将树的根节点插入到链表的头部,然后取队首,进行打印,并出队列,然后将刚出队列的元素的左右孩子入队列,然后再取队首元素,重复上面的操作,详细过程如图所示


 86 //层序遍历树
 87 void TreeLevelOrder(TreeNode* root)
 88 {
 89     if(root == NULL)
 90     {                                                                                                       
 91         //空树
 92         return ;
 93     }
 94    SeqQueue queue;
 95    SeqQueueInit(&queue);
 96    SeqQueuePush(&queue,root);
 97    TreeNode* cur=NULL;
 98    while(SeqQueueFront(&queue,&cur))
 99    {
100        SeqQueueType front;
101        int ret=SeqQueueFront(&queue,&front);
102        if(ret = 0)
103        {
104            //取队首元素失败,说明队列为空
105            break;
106        }
107        //打印当前值,把当前对手元素出队列
108        printf("%c",front->data);
109        SeqQueuePop(&queue);
110        //把当前左右子树入队列
111        if(front->lchild!=NULL)
112        {
113            SeqQueuePush(&queue,front->lchild);
114        }
115        if(front->rchild!=NULL)
116        {
117            SeqQueuePush(&queue,front->rchild);
118        }
119    }
120    printf("\n");
121 }                                                                                                           
122 

(5)还原一棵树
还原一棵树就是给出一个数组,根据数组的内容,构建出一棵树
这个操作还是要使用递归来完成,详细过程见程序
123 //还原一棵树
124 //输入一个数组(数组对每个元素就是树上对节点)
125 //根据数组内容,构建出一棵树,数组中元素内容符合树对先序遍历结果
126 
127 //辅助递归函数
128 TreeNode* _TreeCreate(TreeNodeType data[],size_t size,size_t* index,TreeNodeType null_node)
129 {
130     if(index == NULL)
131     {
132         //非法输入
133         return NULL;
134     }
135     if(*index >= size)
136     {
137         //数组遍历结束
138         return NULL;
139     }
140     if(data[*index] == null_node)
141     {
142         //空树
143         return NULL;
144     }
145     TreeNode* new_node=CreateTreeNode(data[*index]);
146     //先
147     ++(*index);
148     new_node->lchild=_TreeCreate(data,size,index,null_node);
149     //后
150     ++(*index);
151     new_node->rchild=_TreeCreate(data,size,index,null_node);
152     return new_node;
153 }
154 TreeNode* TreeCreate(TreeNodeType data[] ,size_t size,char null_node)
155 {
156     //1.根据index指向对元素内容创建一个节点
157     //2.先++index后递归的构架新的节点的左子树
158     //3.再++index后递归的构架新的节点的右子树
159     size_t index=0;//表示当前取数组中对那个元素
160     return _TreeCreate(data,size,&index,null_node);//辅助完成递归
161 }
162 
(6)二叉树的拷贝
树的拷贝有两种,一种是浅拷贝,一种是深拷贝
浅拷贝(copy)是指内存是同一块内存,两个对象,相当于是指针赋值,两个对象共享同一块内存
深拷贝(clone)是再申请一块内存,
浅拷贝的优点在于,执行效率高,但是缺点是若改变一处则对所有的对象都生效
深拷贝的优点在于,改变所有的对象都不会受影响,但缺点在于执行效率低
164 //树的拷贝
165 TreeNode* TreeClone(TreeNode* root)
166 {
167     if(root == NULL)                                                                                                               
168     {
169         //空树
170         return NULL;
171     }
172     //按照先序方式遍历
173     TreeNode* new_node=CreateTreeNode(root->data);
174     new_node->lchild=TreeClone(root->lchild);
175     new_node->rchild=TreeClone(root->rchild);
176     return new_node;
177 }
178 
(7)二叉树的销毁
是按照二叉树的后序遍历的方式来进行销毁的
179 //二叉树的销毁
180 void TreeDestroy(TreeNode* root)
181 {
182     if(root == NULL)
183     {
184         //空树
185         return;
186     }
187     //按照后序遍历的方式销毁树
188     TreeNode* lchild=root->lchild;
189     TreeNode* rchild=root->rchild;
190     TreeDestroy(root->lchild);
191     TreeDestroy(root->rchild);
192     DestroyTreeNode(root);
193     return;
194 }
195 
(8)求二叉树节点个数

方法一:使用递归的方式来实现,详细见程序

196 //求二叉树节点个数(方法一)
197 void _TreeSize(TreeNode* root,size_t* size)
198 {
199     if(root == NULL)
200     {
201         //空树
202         return ;
203     }
204     ++(*size);
205     _TreeSize(root->lchild,size);
206     _TreeSize(root->rchild,size);
207 }
208 
209 size_t TreeSize1(TreeNode* root)
210 {
211     size_t size=0;
212     //运用_TreeSize来辅助完成递归
213     _TreeSize(root,&size);
214     return size;
215 }
216 

方法二:直接采用递归的方式来实现
217 //求二叉树节点个数(方法二)
218 //直接采用递归对方法,不如方法一那么直观,但是代码很简单
219 size_t TreeSize2(TreeNode* root)
220 {
221     if(root == NULL)
222     {
223         //空树
224         return 0;
225     }
226     return 1+TreeSize2(root->lchild)+TreeSize2(root->rchild);
227 }
228 

(9)求二叉树叶子节点的个数
叶子节点就是二叉树最下面一层的节点,即没有左右孩子的节点,采用递归的方式来实现
229 //求二叉树叶子节点个数
230 size_t TreeLeafSize(TreeNode* root)
231 {
232     if(root == NULL)
233     {
234         //空树
235         return 0;
236     }
237     if(root->lchild == NULL && root->rchild == NULL)
238     {
239         //root是叶子节点
240         return 1;
241     }
242     //root不是叶子节点
243     //采用递归的方式
244     //叶子节点的个数=左子树叶子节点+右字数叶子节点
245     return TreeLeafSize(root->lchild)+TreeLeafSize(root->rchild);
246 }
247 

(10)求第K层节点的个数
采用递归的方式来实现
248 //求二叉树第K层节点的个数
249 //采用递归的方法
250 size_t TreeKLevelSize(TreeNode* root,int k)
251 {
252     if(root == NULL || k<1)                                                                                                        
253     {
254         //非法操作
255         return 0;
256     }
257     if(k == 1)
258     {
259         return 1;
260     }
261     return TreeKLevelSize(root->lchild,k-1)+TreeKLevelSize(root->rchild,k-1);
262 }
263 

(11)求二叉树的高度
264 //求二叉树的高度
265 size_t TreeHeight(TreeNode* root)
266 {
267     if(root == NULL)
268     {
269         //空树
270         return 0;
271     }
272     size_t lheight=TreeHeight(root->lchild);
273     size_t rheight=TreeHeight(root->rchild);
274     return 1+(lheight>rheight?lheight:rheight);
275 }
276 

(12)在二叉树中查找节点
277 //在二叉树中查找节点,给定一个数值求出对应对指针
278 //假设二叉树中的节点不重复
279 TreeNode* TreeFind(TreeNode* root,TreeNodeType to_find)
280 {
281     if(root == NULL)
282     {
283         //空树
284         return NULL;
285     }
286     if(root->data == to_find)
287     {
288         return root;
289     }
290     TreeNode* lresult=TreeFind(root->lchild,to_find);
291     TreeNode* rresult=TreeFind(root->rchild,to_find);
292     return lresult!=NULL?lresult:rresult;
293 }
294 

(13)求当前节点的父节点
295 //求出当前节点的父节点
296 TreeNode* TreeParent(TreeNode* root,TreeNode* child)
297 {
298     if(root == NULL || child == NULL)
299     {
300         //空树||非法输入
301         return NULL;
302     }
303     if(root->lchild == child || root->rchild == child)
304     {
305         return root;
306     }
307     TreeNode* lresult=TreeParent(root->lchild,child);
308     TreeNode* rresult=TreeParent(root->rchild,child);
309     return lresult!=NULL?lresult:rresult;
310 }

(14)求当前节点的左右孩子节点
312 //返回当前节点的左右子树
313 TreeNode* TreeLChild(TreeNode* node)
314 {
315     if(node == NULL)
316     {
317         return NULL;
318     }
319     return node->lchild;
320 }
321 
322 TreeNode* TreeRChild(TreeNode* node)
323 {
324     if(node == NULL)
325     {
326         return NULL;
327     }
328     return node->rchild;
329 }

猜你喜欢

转载自blog.csdn.net/l_x_y_hh/article/details/80136351