二叉树是基于递归思想建立的,所以我们对其做的操作大部分都得用递归思想。
我们队二叉树进行以下操作:
- 二叉树的遍历
- 根据遍历来创建二叉树
- 二叉树的拷贝,销毁
- 二叉树的节点个数,层数,深度,第K层节点数…
- 二叉树查找元素,双亲,左右孩子
由于我们在根据遍历来创建二叉树时用了队列,所以我们要创建以下:
代码如下:(seqqueue的代码:https://blog.csdn.net/q496958148/article/details/80041078)
Makefile:
[test@localhost dtree]$ cat Makefile
dtree:dtree.c seqqueue.c
gcc $^ -o $@
.PHONY:clean
clean:
rm -f dtree
dtree.h:
#pragma once
#include <stdio.h>
#include <stdlib.h>
#include "seqqueue.h"
#define LINE1 printf("-----------------%s-----------------\n",__FUNCTION__);
typedef char DataType;
typedef struct BinaryTree{
DataType data;
struct BinaryTree* lchild;
struct BinaryTree* rchild;
}BinaryTree;
BinaryTree* CreateNode(DataType value);
void DeleteNode(BinaryTree* node);
void treeInit(BinaryTree* head);
void treepreorder(BinaryTree* head);
void treeiorder(BinaryTree* head);
void treepostorder(BinaryTree* head);
void treelevelorder(BinaryTree* head,seqqueue* queue);
BinaryTree* preorderCreate(DataType buf[],size_t size);
BinaryTree* _preorderCreate(DataType buf[],int* index,size_t size);
void treeDestroy(BinaryTree* head);
BinaryTree* treeCpye(BinaryTree* head);
size_t treeleftSize(BinaryTree* head);
size_t treeNodeSize(BinaryTree* head);
size_t treeKLevelSize(BinaryTree* head,int K);
size_t treeHeight(BinaryTree* head);
BinaryTree* treeFind(BinaryTree* head,DataType value);
BinaryTree* treeLChild(BinaryTree* head);
BinaryTree* treeRChild(BinaryTree* head);
BinaryTree* treeParent(BinaryTree* head,BinaryTree* child);
dtree.c
#include "dtree.h"
#include "seqqueue.h"
//二叉树节点创建
BinaryTree* CreateNode(DataType value)
{
//malloc出来的空间记得释放
BinaryTree* new_node = (BinaryTree*)malloc(sizeof(BinaryTree));
if(new_node == NULL)
{
perror("malloc");
return NULL;
}
new_node->data = value;
new_node->lchild = NULL;
new_node->rchild = NULL;
return new_node;
}
//节点的释放(删除)
void DeleteNode(BinaryTree* node)
{
free(node);
node = NULL;
}
//初始化
void treeInit(BinaryTree* head)
{
if(head == NULL)
{
return;
}
head = NULL;
}
//先序遍历(递归思想)
void treepreorder(BinaryTree* head)
{
if(head == NULL)
{
//printf("# ");
return ;
}
printf("%c ",(head->data)-32);//将小写的字母转化尾大写的
treepreorder(head->lchild);
treepreorder(head->rchild);
}
//中序遍历(递归思想)
void treeiorder(BinaryTree* head)
{
if(head == NULL)
{
return;
}
if(head->lchild != NULL)
{
treeiorder(head->lchild);
}
printf("%c ",(head->data)-32);
if(head->rchild != NULL)
{
treeiorder(head->rchild);
}
}
//后续遍历(递归思想)
void treepostorder(BinaryTree* head)
{
if(head == NULL)
{
return;
}
if(head->lchild != NULL)
{
treepostorder(head->lchild);
}
if(head->rchild != NULL)
{
treepostorder(head->rchild);
}
printf("%c ",(head->data)-32);
}
//层序遍历(我借用了队列的思想,每次遍历一个根节点将其插入队列,并且出队列是将其的左右节点继续入队列)
void treelevelorder(BinaryTree* head,seqqueue* queue)
{
if(head == NULL)
{
return;
}
seqqueuePush(queue,head);//创建一个保存节点的队列(并且将根节点插入队列头)
while(1)
{
BinaryTree* tree = seqqueueGetTop(queue);//取得队列头
printf("%c ",tree->data-32);//打印当前队列头
if(tree->lchild != NULL)
{
seqqueuePush(queue,tree->lchild);//插入刚才打印的左子树
}
if(tree->rchild != NULL)
{
seqqueuePush(queue,tree->rchild);//插入刚才打印的右子树
}
seqqueuePop(queue);//出队列
if(queue->size == 0)//当队列为空时,已经遍历完了
{
return;
}
}
}
//这个函数是专门处理递归中需要不断修改一个值的处理函数
BinaryTree* _preorderCreate(DataType buf[],int* index,size_t size)
{
if(index == NULL)
{
return NULL;
}
if((*index) >= size)
{
return NULL;
}
if(buf[*index] == '#')
{
return NULL;
}
BinaryTree* new_node = CreateNode(buf[*index]);//每次还原一个点就将下标++
++(*index);
new_node->lchild = _preorderCreate(buf,index,size);
++(*index);
new_node->rchild = _preorderCreate(buf,index,size);
return new_node;
}
//给出带有空子树信息的先序遍历数组,来还原二叉树
BinaryTree* preorderCreate(DataType buf[],size_t size)//参数:含有先序遍历的数组和数组的大小
{
if(buf == NULL)
{
return NULL;
}
int index = 0;//数组的访问下标
return _preorderCreate(buf,&index,size);//为了线程安全这个概念,(定义全局变量在多线程中不安全,锁的应用)
}
//销毁二叉树(递归删除,我采用后续遍历)
void treeDestroy(BinaryTree* head)
{
if(head == NULL)
{
return;
}
treeDestroy(head->lchild);
treeDestroy(head->rchild);
DeleteNode(head);
}
//二叉树拷贝(深拷贝和浅拷贝的思想,这采用的是深拷贝)
BinaryTree* treeCopy(BinaryTree* head)
{
if(head == NULL)
{
return NULL;
}
BinaryTree* new_node = CreateNode(head->data);
new_node->lchild = treeCopy(head->lchild);
new_node->rchild = treeCopy(head->rchild);
return new_node;
}
//求二叉树的总节点数(递归思想)
size_t treeNodeSize(BinaryTree* head)
{
if(head == NULL)
{
return;
}
return 1 + treeNodeSize(head->lchild) + treeNodeSize(head->rchild);
}
//求叶子节点的个数(递归思想)
size_t treeleftSize(BinaryTree* head)
{
if(head == NULL)
{
return 0;
}
if(head->lchild == NULL && head->rchild == NULL)
{
return 1;
}
return treeleftSize(head->lchild) + treeleftSize(head->rchild);
}
//求第K层的节点数(也是递归思想,根节点的K层,就是根节点子树的K-1层,一直到1层就是当前所求的层了)
size_t treeKLevelSize(BinaryTree* head,int K)
{
if(head == NULL)
{
return 0;
}
if(K == 1)
{
return 1;
}
return treeKLevelSize(head->lchild,K-1) + treeKLevelSize(head->rchild,K-1);
}
//求树的高度
size_t treeHeight(BinaryTree* head)
{
if(head == NULL)
{
return 0;
}
size_t lheight = treeHeight(head->lchild);
size_t rheight = treeHeight(head->rchild);
return 1+(lheight>rheight? lheight:rheight);
}
//查找元素在树中的节点
BinaryTree* treeFind(BinaryTree* head,DataType value)
{
if(head == NULL)
{
return NULL;
}
if(head->data == value)
{
return head;
}
BinaryTree* lfind = treeFind(head->lchild,value);
BinaryTree* rfind = treeFind(head->rchild,value);
if(lfind != NULL)
{
return lfind;
}
if(rfind != NULL)
{
return rfind;
}
return NULL;
}
//查左子树
BinaryTree* treeLChild(BinaryTree* head)
{
if(head == NULL)
{
return NULL;
}
return head->lchild;
}
//查右子树
BinaryTree* treeRChild(BinaryTree* head)
{
if(head == NULL)
{
return NULL;
}
return head->rchild;
}
//查双亲节点
BinaryTree* treeParent(BinaryTree* head,BinaryTree* child)
{
if(head == NULL || child == NULL)
{
return NULL;
}
if(head == child)
{
return NULL;
}
if(head->lchild == child || head->rchild == child )
{
return head;
}
BinaryTree* lchild = treeParent(head->lchild,child);
BinaryTree* rchild = treeParent(head->rchild,child);
return lchild != NULL? lchild:rchild;//三目操作符
}
//------------------------------------------------------------------
//------测试函数
//------------------------------------------------------------------
void testtreeorder()
{
LINE1;
BinaryTree* a = CreateNode('a');
BinaryTree* b = CreateNode('b');
BinaryTree* c = CreateNode('c');
BinaryTree* d = CreateNode('d');
BinaryTree* e = CreateNode('e');
BinaryTree* f = CreateNode('f');
BinaryTree* g = CreateNode('g');
a->lchild = b;
a->rchild = c;
b->lchild = d;
b->rchild = e;
e->lchild = g;
c->rchild = f;
printf("三种常见遍历:\n");
printf("先序遍历:");
treepreorder(a);
printf("\n");
printf("中序遍历:");
treeiorder(a);
printf("\n");
printf("后序遍历:");
treepostorder(a);
printf("\n");
}
void testtreelevorder()
{
LINE1;
BinaryTree* a = CreateNode('a');
BinaryTree* b = CreateNode('b');
BinaryTree* c = CreateNode('c');
BinaryTree* d = CreateNode('d');
BinaryTree* e = CreateNode('e');
BinaryTree* f = CreateNode('f');
BinaryTree* g = CreateNode('g');
a->lchild = b;
a->rchild = c;
b->lchild = d;
b->rchild = e;
e->lchild = g;
c->rchild = f;
printf("层序遍历:\n");
seqqueue queue;
seqqueueInit(&queue);
printf("层序遍历:");
treelevelorder(a,&queue);
printf("\n");
}
void testpreorderCreate()
{
LINE1;
DataType buf[] = "abd##eg###c#f##";
size_t size = sizeof(buf)/sizeof(buf[0]) - 1;
BinaryTree* head = preorderCreate(buf,size);
printf("根据先序遍历还原二叉树:\n");
printf("先序遍历:");
treepreorder(head);
printf("\n");
printf("中序遍历:");
treeiorder(head);
printf("\n");
printf("后序遍历:");
treepostorder(head);
printf("\n");
}
void testtreeCopy()
{
LINE1;
DataType buf[] = "abd##eg###c#f##";
size_t size = sizeof(buf)/sizeof(buf[0]) - 1;
BinaryTree* head = preorderCreate(buf,size);
BinaryTree* new_node = treeCopy(head);
printf("二叉树拷贝:\n");
printf("先序遍历:");
treepreorder(new_node);
printf("\n");
printf("中序遍历:");
treeiorder(new_node);
printf("\n");
printf("后序遍历:");
treepostorder(new_node);
printf("\n");
}
void testtreeNodeSize()
{
LINE1;
DataType buf[] = "abd##eg###c#f##";
size_t size = sizeof(buf)/sizeof(buf[0]) - 1;
BinaryTree* head = preorderCreate(buf,size);
printf("二叉树节点总数:%d\n",treeNodeSize(head));
}
void testtreeleftSize()
{
LINE1;
DataType buf[] = "abd##eg###c#f##";
size_t size = sizeof(buf)/sizeof(buf[0]) - 1;
BinaryTree* head = preorderCreate(buf,size);
printf("二叉树叶子节点总数:%d\n",treeleftSize(head));
}
void testtreeKLevelSize()
{
LINE1;
int K = 3;
DataType buf[] = "abd##eg###c#f##";
size_t size = sizeof(buf)/sizeof(buf[0]) - 1;
BinaryTree* head = preorderCreate(buf,size);
printf("二叉树第%d层节点总数:%d\n",K,treeKLevelSize(head,K));
}
void testtreeHeight()
{
LINE1;
DataType buf[] = "abd##eg###c#f##";
size_t size = sizeof(buf)/sizeof(buf[0]) - 1;
BinaryTree* head = preorderCreate(buf,size);
printf("二叉树深度:%d\n",treeHeight(head));
}
void testtreeFind()
{
LINE1;
DataType buf[] = "abd##eg###c#f##";
size_t size = sizeof(buf)/sizeof(buf[0]) - 1;
BinaryTree* head = preorderCreate(buf,size);
printf("寻找元素在二叉树中的节点:\n");
BinaryTree* cur = treeFind(head,'f');
printf("正常测试\n");
printf("预计值:[%c|%p],实际值:[%c|%p]\n",head->rchild->rchild->data
,&(head->rchild->rchild->data),cur->data,&(cur->data));
BinaryTree* cur1 = treeFind(head,'z');
printf("错误测试\n");
printf("预计值: NULL ,实际值:%p\n",cur1);;
}
void testtreeChild()
{
LINE1;
BinaryTree* a = CreateNode('a');
BinaryTree* b = CreateNode('b');
BinaryTree* c = CreateNode('c');
BinaryTree* d = CreateNode('d');
BinaryTree* e = CreateNode('e');
BinaryTree* f = CreateNode('f');
BinaryTree* g = CreateNode('g');
a->lchild = b;
a->rchild = c;
b->lchild = d;
b->rchild = e;
e->lchild = g;
c->rchild = f;
BinaryTree* lchild = treeLChild(b);
BinaryTree* rchild = treeRChild(b);
BinaryTree* lchild1 = treeLChild(f);
BinaryTree* rchild1 = treeRChild(f);
printf("求节点的左右节点:\n");
printf("正常测试\n");
printf("左节点预计值:[%c|%p],实际值[%c|%p]\n",
b->lchild->data,&(b->lchild->data),lchild->data,&(lchild->data));
printf("右节点预计值:[%c|%p],实际值:[%c|%p]\n",
b->rchild->data,&(b->rchild->data),rchild->data,&(rchild->data));
printf("错误测试\n");
printf("左节点预计值: NULL ,实际值:%p\n",lchild1);
printf("右节点预计值: NULL ,实际值:%p\n",rchild1);
}
void testtreeParent()
{
LINE1;
BinaryTree* a = CreateNode('a');
BinaryTree* b = CreateNode('b');
BinaryTree* c = CreateNode('c');
BinaryTree* d = CreateNode('d');
BinaryTree* e = CreateNode('e');
BinaryTree* f = CreateNode('f');
BinaryTree* g = CreateNode('g');
a->lchild = b;
a->rchild = c;
b->lchild = d;
b->rchild = e;
e->lchild = g;
c->rchild = f;
BinaryTree* parent = treeParent(a,g);
printf("求节点的双亲节点:\n");
printf("预计值:[%c|%p],实际值:[%c|%p]\n",e->data,&(e->data),parent->data,&(parent->data));
}
int main()
{
testtreeorder();
testtreelevorder();
testpreorderCreate();
testtreeCopy();
testtreeNodeSize();
testtreeleftSize();
testtreeKLevelSize();
testtreeHeight();
testtreeFind();
testtreeChild();
testtreeParent();
return 0;
}