链式二叉树

       

目录

1.二叉树的结构体结点

2.二叉树的创建

3.二叉树的遍历

3.1.前中后序遍历

3.2.层序遍历

4.判断是否为完全二叉树

5.完整代码


        链式二叉树是实现二叉树的一种常规方法,普通链式二叉树虽然没有现实意义,但是自己写一次对于初学者理解二叉树有较大的帮助,这里我就讲讲链式二叉树的一些重要函数的实现。

1.二叉树的结构体结点

        二叉树的结构体十分简单,只有三部分,根结点和其左右孩子

typedef struct BinaryTreeNode
{
	BTDataType _data;
	struct BinaryTreeNode* _left;
	struct BinaryTreeNode* _right;
}BTNode;

这个很简单,我就不多讲了。

2.二叉树的创建

        二叉树的创建有一种比较原始的方法就是自己手搓一个,这种方法很费劲,但是在测试代码时有一定的作用,如下:

BTNode* p1 = (BTNode*)malloc(sizeof(BTNode));
BTNode* p2 = (BTNode*)malloc(sizeof(BTNode));
BTNode* p3 = (BTNode*)malloc(sizeof(BTNode));
BTNode* p4 = (BTNode*)malloc(sizeof(BTNode));
BTNode* p5 = (BTNode*)malloc(sizeof(BTNode));
BTNode* p6 = (BTNode*)malloc(sizeof(BTNode));
p1->_data = 1;
p1->_left = p2;
p1->_right = p3;
p2->_data = 2;
p2->_left = p4;
p2->_right = p5;
p3->_data = 3;
p3->_left = p6;
p3->_right = NULL;
p4->_data = 4;
p4->_left = NULL;
p4->_right = NULL;
p5->_data = 5;
p5->_left = NULL;
p5->_right = NULL;
p6->_data = 6;
p6->_left = NULL;
p6->_right = NULL;

这里创建了如下图所示的二叉树

         当然,正常使用我们显然不能使用这种方法,我采用的是通过其前序遍历生成的数组反向生成树的方法,代码如下:

// 通过前序遍历的数组"ABD##E#H##CF##G##"构建二叉树
BTNode* BinaryTreeCreate(BTDataType* a, int n, int* pi)
{		
	if (a[(*pi)] == '#')
	{
		(*pi)++;
		return NULL;
	}
	BTNode* root = (BTNode*)malloc(sizeof(BTNode));
	if (!root)
	{
		perror("malloc fail");
		exit(0);
	}
	root->_data = a[(*pi)++];//给根节点赋值
	
	root->_left=BinaryTreeCreate(a, n, pi);
    //给左孩子赋值
	
    root->_right=BinaryTreeCreate(a, n, pi);
    //给右孩子赋值
	
    return root;

	
}

此处函数的参数的意义分别为:BTDataType* a       // 前序遍历得到的数组

                                                   int n                        //数组的大小(此函数中没什么作用)

                                                   int* pi                      //此时赋值给结点的数组元素的索引

看到这里,可能有人会疑惑,为什么要用  int *pi,不直接使用   int pi,这是因为这是一个递归函数,倘若我们使用一个int 值,对于每次需要使用的索引不能够判断,但是使用   int  *pi,每次使用完我们直接修改其本身值,下次调用就直接是修改后的值。

3.二叉树的遍历

3.1.前中后序遍历

        二叉树的前序,中序,后序遍历十分简单,无非是一种简单的递归,他们都是二叉树深度优先遍历(DFS)的一种,代码如下:

// 二叉树前序遍历 
void BinaryTreePrevOrder(BTNode* root)
{
	if (root == NULL)
	{
		return;
	}
	printf("%c ", root->_data);
	BinaryTreePrevOrder(root->_left);
	BinaryTreePrevOrder(root->_right);
}

// 二叉树中序遍历
void BinaryTreeInOrder(BTNode* root)
{
	if (root == NULL)
	{
		return;
	}
	
	BinaryTreeInOrder(root->_left);
	printf("%c ", root->_data);
	BinaryTreeInOrder(root->_right);
}

// 二叉树后序遍历
void BinaryTreePostOrder(BTNode* root)
{
	if (root == NULL)
	{
		return;
	}

	BinaryTreePostOrder(root->_left);
	BinaryTreePostOrder(root->_right);
	printf("%c ", root->_data);

}

3.2.层序遍历

        层序遍历是链式二叉树较难的一种遍历方式,难点就是层序遍历需要把二叉树和队列结合起来,规则就是:根节点出队列,此根节点的左右孩子就入队列。并且,链式二叉树的层序遍历是二叉树的广度优先遍历(BFS)的一种。代码如下:

//层序遍历我选择使用数组模拟循环队列的方法


//循环链表结构体
#define CQUEUESIZE 12//如果需要修改循环队列大小,直接修改CQUEUESIZE的define
struct CycleQueue
{
	int front;
	int rear;
	BTNode* elem[CQUEUESIZE];
};//循环队列



//入队列
void Push(CycleQueue* node, BTNode* x)
{
	
    //之所以这里没有排除node==NULL的情况,是因为在判断完全二叉树功能时有作用
    if ((node->rear + 1) % CQUEUESIZE == node->front)
	{
		printf("循环队列已满\n");
		exit(0);
	}

	node->elem[node->rear] = x;
	node->rear = (node->rear + 1) % CQUEUESIZE;
}


//判断队列是否为空
bool Empty(CycleQueue* node)
{
	assert(node);
	if (node->front == node->rear)
	{
		return true;
	}
	return false;
}


//出队列
void Pop(CycleQueue* node)
{
	if (Empty(node))
	{
		return;
	}
	node->front = (node->front + 1) % CQUEUESIZE;
}




// 层序遍历
void BinaryTreeLevelOrder(BTNode* root)
{
	
	if (root == NULL)
	{
		return;
	}
	
	CycleQueue* CQueue = (CycleQueue*)malloc(sizeof(CycleQueue));
	if (!CQueue)
	{
		perror("malloc fail");
		exit(0);
	}
	
	CQueue->front = 0;
	CQueue->rear = 0;
	BTNode *p=root;

	if(root!=NULL)
	Push(CQueue, p);
	

	while (!Empty(CQueue))
	{

		printf("%c ", p->_data);
		if (p->_left)
			Push(CQueue, p->_left);
		if (p->_right)
			Push(CQueue, p->_right);
		Pop(CQueue);
		if (!Empty(CQueue))
			p= CQueue->elem[CQueue->front];

	}
	
	free(CQueue);
	CQueue = NULL;
}


若大家对于循环队列有疑惑,可以看我的另一篇博客

http://t.csdn.cn/VQDkz

4.判断是否为完全二叉树

        完全二叉树是一种特殊的树,除了最后两层可能有叶子结点,其他层不会有叶子结点,在层序遍历中,它也具有特殊性,如下图

 按层序遍历为 :1  2  3  4  5  6  NULL  NULL NULL NULL NULL NULL NULL

我们可以发现,在层序遍历中,如果出现NULL,接下来都是NULL,也就是是NULL是连续到结束的,这也是入队列我不排除入队列元素为NULL的原因。

代码如下:

int BinaryTreeComplete(BTNode* root)
{
	if (root == NULL)//如果树为NULL
	{
		return 1;
	}

	CycleQueue* CQueue = (CycleQueue*)malloc(sizeof(CycleQueue));
	if (!CQueue)
	{
		perror("malloc fail");
		exit(0);
	}
	CQueue->front = 0;
	CQueue->rear = 0;

	if (root != NULL)
		Push(CQueue, root);


	while (!Empty(CQueue))
	{
		BTNode* p = CQueue->elem[CQueue->front];
		if (p)//如果队列头不是NULL,入其左右孩子
		{
			Push(CQueue, p->_left);
			Push(CQueue, p->_right);
			Pop(CQueue);
		}
		else//如果队列头为NULL,判断NULL是否是连续的
		{
			while (!Empty(CQueue))
			{
				BTNode* flag = CQueue->elem[CQueue->front];
				if (flag)//如果出现不是NULL的指针,说明NULL不连续,不是完全二叉树
				{
					return 0;
				}
				Pop(CQueue);
			}
            //while结束,说明NULL是连续到结束的
			return 1;
		}

	}
    //使用完动态开辟的空间不要忘了free
	free(CQueue);
	CQueue = NULL;

}

其他函数都是使用递归的方法解决,比较简单,我就不一一说明,大家可以自行查看注释。

5.完整代码


//BinaryTree.h 文件

#pragma once
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
#include<string.h>

#define CQUEUESIZE 12
typedef char BTDataType;



typedef struct BinaryTreeNode
{
	BTDataType _data;
	struct BinaryTreeNode* _left;
	struct BinaryTreeNode* _right;
}BTNode;


struct CycleQueue
{
	int front;
	int rear;
	BTNode* elem[CQUEUESIZE];
};//循环队列


// 通过前序遍历的数组"ABD##E#H##CF##G##"构建二叉树
BTNode* BinaryTreeCreate(BTDataType* a, int n, int* pi);

// 二叉树销毁
void BinaryTreeDestory(BTNode** root);

// 二叉树节点个数
int BinaryTreeSize(BTNode* root);

// 二叉树叶子节点个数
int BinaryTreeLeafSize(BTNode* root);

// 二叉树第k层节点个数
int BinaryTreeLevelKSize(BTNode* root, int k);

// 二叉树查找值为x的节点
BTNode* BinaryTreeFind(BTNode* root, BTDataType x);

// 二叉树前序遍历 
void BinaryTreePrevOrder(BTNode* root);

// 二叉树中序遍历
void BinaryTreeInOrder(BTNode* root);

// 二叉树后序遍历
void BinaryTreePostOrder(BTNode* root);

// 层序遍历
void BinaryTreeLevelOrder(BTNode* root);

// 判断二叉树是否是完全二叉树
int BinaryTreeComplete(BTNode* root);

//循环队列插入函数
void Push(CycleQueue* node, BTNode* x);

//判断循环队列是否为空
bool Empty(CycleQueue* node);

//循环队列删除函数
void Pop(CycleQueue* node);









//BinaryTree.cpp 文件


#include"BinaryTree.h"


// 通过前序遍历的数组"ABD##E#H##CF##G##"构建二叉树
BTNode* BinaryTreeCreate(BTDataType* a, int n, int* pi)
{		
	if (a[(*pi)] == '#')
	{
		(*pi)++;
		return NULL;
	}
	BTNode* root = (BTNode*)malloc(sizeof(BTNode));
	if (!root)
	{
		perror("malloc fail");
		exit(0);
	}
	root->_data = a[(*pi)++];
	
	root->_left=BinaryTreeCreate(a, n, pi);
	root->_right=BinaryTreeCreate(a, n, pi);
	return root;

	
}


// 二叉树销毁
void BinaryTreeDestory(BTNode** root)
{
	if (*root == NULL)
	{
		return;
	}
	if((*root)->_left)
	BinaryTreeDestory(&((*root)->_left));
	
	if((*root)->_right)
	BinaryTreeDestory(&((*root)->_right));
	free(*root);
	*root = NULL;
	
}

// 二叉树节点个数
int BinaryTreeSize(BTNode* root)
{
	if (root == NULL)
	{
		return 0;
	}
	return BinaryTreeSize(root->_left) +
		BinaryTreeSize(root->_right) + 1;
}

// 二叉树叶子节点个数
int BinaryTreeLeafSize(BTNode* root)
{
	if (root == NULL)
	{
		return 0;
	}
	if (root->_left == root->_right && root->_left == NULL)
	{
		return 1;
	}
	return BinaryTreeLeafSize(root->_left) +
		BinaryTreeLeafSize(root->_right);
}

// 二叉树第k层节点个数
int BinaryTreeLevelKSize(BTNode* root, int k)
{
	if (root == NULL)
	{
		return 0;
	}
	if (k == 1)
	{
		return 1;
	}
	int leftK = BinaryTreeLevelKSize(root->_left, k - 1);
	int rightK = BinaryTreeLevelKSize(root->_right, k - 1);
	return  leftK + rightK;

}

// 二叉树查找值为x的节点
BTNode* BinaryTreeFind(BTNode* root, BTDataType x)
{
	if (root == NULL)
	{
		return NULL;
	}
	if (root->_data == x)
	{
		return root;
	}
	BTNode* left = BinaryTreeFind(root->_left, x);
	if (left)
		return left;
	BTNode* right = BinaryTreeFind(root->_right, x);
	if (right)
		return right;
	return NULL;
}

// 二叉树前序遍历 
void BinaryTreePrevOrder(BTNode* root)
{
	if (root == NULL)
	{
		return;
	}
	printf("%c ", root->_data);
	BinaryTreePrevOrder(root->_left);
	BinaryTreePrevOrder(root->_right);
}

// 二叉树中序遍历
void BinaryTreeInOrder(BTNode* root)
{
	if (root == NULL)
	{
		return;
	}
	
	BinaryTreeInOrder(root->_left);
	printf("%c ", root->_data);
	BinaryTreeInOrder(root->_right);
}

// 二叉树后序遍历
void BinaryTreePostOrder(BTNode* root)
{
	if (root == NULL)
	{
		return;
	}

	BinaryTreePostOrder(root->_left);
	BinaryTreePostOrder(root->_right);
	printf("%c ", root->_data);

}


//层序遍历我选择使用数组模拟循环队列的方法


void Push(CycleQueue* node, BTNode* x)
{
	if ((node->rear + 1) % CQUEUESIZE == node->front)
	{
		printf("循环队列已满\n");
		exit(0);
	}

	node->elem[node->rear] = x;
	node->rear = (node->rear + 1) % CQUEUESIZE;
}

bool Empty(CycleQueue* node)
{
	assert(node);
	if (node->front == node->rear)
	{
		return true;
	}
	return false;
}

void Pop(CycleQueue* node)
{
	if (Empty(node))
	{
		return;
	}
	node->front = (node->front + 1) % CQUEUESIZE;
}


// 判断二叉树是否是完全二叉树
int BinaryTreeComplete(BTNode* root)
{
	int x = 1;
	if (root == NULL)
	{
		return 1;
	}

	CycleQueue* CQueue = (CycleQueue*)malloc(sizeof(CycleQueue));
	if (!CQueue)
	{
		perror("malloc fail");
		exit(0);
	}
	CQueue->front = 0;
	CQueue->rear = 0;

	if (root != NULL)
		Push(CQueue, root);


	while (!Empty(CQueue))
	{
		BTNode* p = CQueue->elem[CQueue->front];
		if (p)
		{
			Push(CQueue, p->_left);
			Push(CQueue, p->_right);
			Pop(CQueue);
		}
		else
		{
			while (!Empty(CQueue))
			{
				BTNode* flag = CQueue->elem[CQueue->front];
				if (flag)
				{
					return 0;
				}
				Pop(CQueue);
			}
			return 1;
		}



	}

	free(CQueue);
	CQueue = NULL;



}
// 层序遍历
void BinaryTreeLevelOrder(BTNode* root)
{
	
	if (root == NULL)
	{
		return;
	}
	
	CycleQueue* CQueue = (CycleQueue*)malloc(sizeof(CycleQueue));
	if (!CQueue)
	{
		perror("malloc fail");
		exit(0);
	}
	
	CQueue->front = 0;
	CQueue->rear = 0;
	BTNode *p=root;

	if(root!=NULL)
	Push(CQueue, p);
	

	while (!Empty(CQueue))
	{

		printf("%c ", p->_data);
		if (p->_left)
			Push(CQueue, p->_left);
		if (p->_right)
			Push(CQueue, p->_right);
		Pop(CQueue);
		if (!Empty(CQueue))
			p= CQueue->elem[CQueue->front];

	}
	
	free(CQueue);
	CQueue = NULL;
}






int main()
{
	char string[] = "ABD##E#H##CF##G##";
	int n = strlen(string);
	int p = 0;
	int* pi = &p;
	BTNode* root = BinaryTreeCreate(string, n, pi);

	printf("前序遍历为:\n");
	BinaryTreePrevOrder(root);
	
	printf("\n中序遍历为:\n");
	BinaryTreeInOrder(root);
	
	printf("\n后序遍历为:\n");
	BinaryTreePostOrder(root);

	printf("\n层序遍历为:\n");
	BinaryTreeLevelOrder(root);
	
	printf("\n二叉树结点个数为 :%d\n", BinaryTreeSize(root));
	printf("叶子结点数为:%d\n", BinaryTreeLeafSize(root));

	
	printf("二叉树第1层结点个数为 :%d\n", BinaryTreeLevelKSize(root, 1));
	printf("二叉树第2层结点个数为 :%d\n", BinaryTreeLevelKSize(root, 2));
	printf("二叉树第3层结点个数为 :%d\n", BinaryTreeLevelKSize(root, 3));

	printf("查找值为G的结点,G的地址为:%p\n", BinaryTreeFind(root, 'G'));
	
	int i = BinaryTreeComplete(root);
	if (i)
	{
		printf("此树是完全二叉树\n");
	}
	else
	{
		printf("此树不是完全二叉树\n");

	}

	BinaryTreeDestory(&root);
	printf("\n二叉树销毁成功\n");
	return 0;
}




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值