堆与二叉树

1.树概念及结构

1.1 树的概念

树是一种 非线性 的数据结构,它是由 n n>=0 )个有限结点组成一个具有层次关系的集合。 把它叫做树是因
为它看起来像一棵倒挂的树,也就是说它是根朝上,而叶朝下的
有一个 特殊的结点,称为根结点 ,根节点没有前驱结点
除根节点外, 其余结点被分成 M(M>0) 个互不相交的集合 T1 T2 …… Tm ,其中每一个集合 Ti(1<= i <= m)又是一棵结构与树类似的子树。每棵子树的根结点有且只有一个前驱,可以有 0 个或多个后继 。因此,树是递归定义 的。
注意:树形结构中,子树之间不能有交集,否则就不是树形结构

1.2 树的相关概念

节点的度 :一个节点含有的子树的个数称为该节点的度; 如上图: A 的为 6
叶节点或终端节点 :度为 0 的节点称为叶节点; 如上图: B C H I... 等节点为叶节点
非终端节点或分支节点 :度不为 0 的节点; 如上图: D E F G... 等节点为分支节点
双亲节点或父节点 :若一个节点含有子节点,则这个节点称为其子节点的父节点; 如上图: A B 的父节点
孩子节点或子节点 :一个节点含有的子树的根节点称为该节点的子节点; 如上图: B A 的孩子节点
兄弟节点 :具有相同父节点的节点互称为兄弟节点; 如上图: B C 是兄弟节点
树的度 :一棵树中,最大的节点的度称为树的度; 如上图:树的度为 6
节点的层次 :从根开始定义起,根为第 1 层,根的子节点为第 2 层,以此类推;
树的高度或深度 :树中节点的最大层次; 如上图:树的高度为 4
堂兄弟节点 :双亲在同一层的节点互为堂兄弟;如上图: H I 互为兄弟节点
节点的祖先 :从根到该节点所经分支上的所有节点;如上图: A 是所有节点的祖先
子孙 :以某节点为根的子树中任一节点都称为该节点的子孙。如上图:所有节点都是 A 的子孙
森林 :由 m m>0 )棵互不相交的树的集合称为森林;

1.3 树的表示

树结构相对线性表就比较复杂了,要存储表示起来就比较麻烦了, 既然保存值域,也要保存结点和结点之间 的关系 ,实际中树有很多种表示方式如:双亲表示法,孩子表示法、孩子双亲表示法以及孩子兄弟表示法等。我们这里就简单的了解其中最常用的孩子兄弟表示法
typedef int DataType;
struct Node
{
 struct Node* _firstChild1; // 第一个孩子结点
 struct Node* _pNextBrother; // 指向其下一个兄弟结点
 DataType _data; // 结点中的数据域
};

2.二叉树概念及结构

2.1概念

一棵二叉树是结点的一个有限集合,该集合 :
1. 或者为空
2. 由一个根节点加上两棵别称为左子树和右子树的二叉树组成
二叉树的特点有:
1. 二叉树不存在度大于 2 的结点
2. 二叉树的子树有左右之分,次序不能颠倒,因此二叉树是有序树

2.2 特殊的二叉树:

1. 满二叉树 :一个二叉树,如果每一个层的结点数都达到最大值,则这个二叉树就是满二叉树。也就是
说,如果一个二叉树的层数为 K ,且结点总数是
,则它就是满二叉树。
2. 完全二叉树 :完全二叉树是效率很高的数据结构,完全二叉树是由满二叉树而引出来的。对于深度为 K
的,有 n 个结点的二叉树,当且仅当其每一个结点都与深度为 K 的满二叉树中编号从 1 n 的结点一一对
应时称之为完全二叉树。 要注意的是满二叉树是一种特殊的完全二叉树。

2.3 二叉树的性质

1. 若规定根节点的层数为 1 ,则一棵非空二叉树的 i 层上最多有2^(i-1)个结点.
2. 若规定根节点的层数为 1 ,则 深度为 h 的二叉树的最大结点数是2^h-1
.3. 对任何一棵二叉树 , 如果度为 0 其叶结点个数为n0  , 度为 2 的分支结点个数为n2  , 则有 n0= n2+ 1
4. 若规定根节点的层数为 1 ,具有 n 个结点的满二叉树的深度 h= log2(n+1)
5. 对于具有 n 个结点的完全二叉树,如果按照从上至下从左至右的数组顺序对所有节点从 0 开始编号,则对 于序号为i 的结点有:
1. i>0 i 位置节点的双亲序号: (i-1)/2 i=0 i 为根节点编号,无双亲节点
2. 2i+1<n ,左孩子序号: 2i+1 2i+1>=n 否则无左孩子
3. 2i+2<n ,右孩子序号: 2i+2 2i+2>=n 否则无右孩子

2.4 二叉树的存储结构

二叉树一般可以使用两种结构存储,一种顺序结构,一种链式结构。
1. 顺序存储
顺序结构存储就是使用 数组来存储 ,一般使用数组 只适合表示完全二叉树 ,因为不是完全二叉树会有空间的浪费。而现实中使用中只有堆才会使用数组来存储,关于堆我们后面的章节会专门讲解。二叉树顺 序存储在物理上是一个数组,在逻辑上是一颗二叉树。
2. 链式存储
二叉树的链式存储结构是指,用链表来表示一棵二叉树,即用链来指示元素的逻辑关系。 通常的方法是链表中每个结点由三个域组成,数据域和左右指针域,左右指针分别用来给出该结点左孩子和右孩子所在的链结点的存储地址 。链式结构又分为二叉链和三叉链,红黑树等会用到三叉链。
typedef int BTDataType;
// 二叉链
struct BinaryTreeNode
{
    struct BinTreeNode* _pLeft; // 指向当前节点左孩子
    struct BinTreeNode* _pRight; // 指向当前节点右孩子
    BTDataType _data; // 当前节点值域
}
// 三叉链
struct BinaryTreeNode
{
    struct BinTreeNode* _pParent; // 指向当前节点的双亲
    struct BinTreeNode* _pLeft; // 指向当前节点左孩子
    struct BinTreeNode* _pRight; // 指向当前节点右孩子
    BTDataType _data; // 当前节点值域
};

3.二叉树的顺序结构及实现

3.1 二叉树的顺序结构

普通的二叉树是不适合用数组来存储的,因为可能会存在大量的空间浪费。而完全二叉树更适合使用顺序结构存储。现实中我们通常把堆 ( 一种二叉树 ) 使用顺序结构的数组来存储,需要注意的是这里的堆和操作系统 虚拟进程地址空间中的堆是两回事,一个是数据结构,一个是操作系统中管理内存的一块区域分段。

3.2 堆的概念及结构

堆的概念:
堆就是以 二叉树的顺序存储方式来存储元素,同时又要满足父亲结点存储数据都要大于儿子结点存储数据(也可以是父亲结点数据都要小于儿子结点数据)的一种数据结构。堆只有两种即大堆和小堆,大堆就是父亲结点数据大于儿子结点数据,小堆则反之。
堆的性质:
堆中某个节点的值总是不大于或不小于其父节点的值;
堆总是一棵完全二叉树。

3.3 堆的实现

3.3.1 堆向下调整算法

如果有一个数组,逻辑上看做一颗完全二叉树。我们通过从根节点开始的向下调整算法可以把它调整成一个小堆。向下调整算法有一个前提:左右子树必须是一个堆,才能调整。
代码如下:
//向下调整算法
void AdjustDown(HPDataType* a, size_t size,int parent)
{
	assert(a);
	int child = parent * 2 + 1;
	while (child < size)
	{
		if (child + 1 < size && a[child + 1] > a[child])
		{
			child += 1;
		}
		if (a[child] > a[parent])
		{
			Swap(&a[child], &a[parent]);
			parent = child;
			child = 2 * parent + 1;
		}
		else
		{
			break;
		}
	}
}

3.3.2 堆的向上调整算法

当我们在一个堆的末尾插入一个数据后,需要对堆进行调整,使其仍然是一个堆,这时需要用到堆的向上调整算法。

代码如下:

//向上调整算法
void AdjustUp(HPDataType* a, size_t child)
{
	assert(a);
	while (child > 0)
	{
		size_t parent = (child - 1) / 2;
		if (a[parent] < a[child])
		{
			Swap(&a[parent], &a[child]);
		}
		else
		{
			break;
		}
		child = parent;
	}
}

3.3.3 堆的创建

如果有一个数组,这个数组逻辑上可以看做一颗完全二叉树,但是还不是一个堆,现在我们通过算法,把它构建成一个堆。根节点左右子树不是堆,我们怎么调整呢?这里我们从倒数的第一个非叶子节点的子树开始调整,一直调整到根节点的树,就可以调整成堆。
代码如下:
void HeapCreate(Heap* hp, HPDataType* a, int n)
{
	assert(hp);
	HeapInit(hp);
	hp->_a = (HPDataType*)malloc(sizeof(HPDataType) * n);
	for (int i = 0; i < n; i++)
	{
		HeapPush(hp, a[i]);
	}
}

3.3.4 堆排序

堆排序即利用堆的思想来进行排序,总共分为两个步骤:
1. 建堆
升序:建大堆
降序:建小堆
2. 利用堆删除思想来进行排序
建堆和堆删除中都用到了向下调整,因此掌握了向下调整,就可以完成堆排序。

3.3.5 TOP-K问题

TOP-K 问题:即求数据结合中前 K 个最大的元素或者最小的元素,一般情况下数据量都比较大
比如:专业前 10 名、世界 500 强、富豪榜、游戏中前 100 的活跃玩家等。
对于 Top-K 问题,能想到的最简单直接的方式就是排序,但是:如果数据量非常大,排序就不太可取了 ( 可能数据都不能一下子全部加载到内存中) 。最佳的方式就是用堆来解决,基本思路如下:
1. 用数据集合中前 K 个元素来建堆
k 个最大的元素,则建小堆
k 个最小的元素,则建大堆
2. 用剩余的 N-K 个元素依次与堆顶元素来比较,不满足则替换堆顶元素,将剩余N-K 个元素依次与堆顶元素比完之后,堆中剩余的 K 个元素就是所求的前 K 个最小或者最大的元素。

 3.3.6 堆的代码实现

Heap.h
#pragma once
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
#include<time.h>
typedef int HPDataType;
typedef struct Heap
{
	HPDataType* _a;
	int _size;
	int _capacity;
}Heap;

//实现大堆
//堆的初始化
void HeapInit(Heap* hp);
//向上调整算法
void AdjustUp(HPDataType* a, size_t child);
//向下调整算法
void AdjustDown(HPDataType* a, size_t size,int parent);
// 堆的构建
void HeapCreate(Heap* hp, HPDataType* a, int n);
// 堆的销毁
void HeapDestory(Heap* hp);
// 堆的插入
void HeapPush(Heap* hp, HPDataType x);
// 堆的删除
void HeapPop(Heap* hp);
// 取堆顶的数据
HPDataType HeapTop(Heap* hp);
// 堆的数据个数
int HeapSize(Heap* hp);
// 堆的判空
int HeapEmpty(Heap* hp);
Heap.c
#include"Heap.h"

//实现小堆
//堆的初始化
void HeapInit(Heap* hp)
{
	assert(hp);
	hp->_a = NULL;
	hp->_size = hp->_capacity = 0;
}
//交换两个数的位置
void Swap(HPDataType* a, HPDataType* b)
{
	assert(a && b);
	HPDataType tmp = *a;
	*a = *b;
	*b = tmp;
}
//向上调整算法
void AdjustUp(HPDataType* a, size_t child)
{
	assert(a);
	while (child > 0)
	{
		size_t parent = (child - 1) / 2;
		if (a[parent] < a[child])
		{
			Swap(&a[parent], &a[child]);
		}
		else
		{
			break;
		}
		child = parent;
	}
}
//向下调整算法
void AdjustDown(HPDataType* a, size_t size,int parent)
{
	assert(a);
	int child = parent * 2 + 1;
	while (child < size)
	{
		if (child + 1 < size && a[child + 1] > a[child])
		{
			child += 1;
		}
		if (a[child] > a[parent])
		{
			Swap(&a[child], &a[parent]);
			parent = child;
			child = 2 * parent + 1;
		}
		else
		{
			break;
		}
	}
}
// 堆的构建
void HeapCreate(Heap* hp, HPDataType* a, int n)
{
	assert(hp);
	HeapInit(hp);
	hp->_a = (HPDataType*)malloc(sizeof(HPDataType) * n);
	for (int i = 0; i < n; i++)
	{
		HeapPush(hp, a[i]);
	}
}
// 堆的销毁
void HeapDestory(Heap* hp)
{
	assert(hp);
	free(hp->_a);
	hp->_a = NULL;
	hp->_capacity = hp->_size = 0;
}
// 堆的插入
void HeapPush(Heap* hp, HPDataType x)
{
	assert(hp);
	if (hp->_capacity == hp->_size)
	{
		int newcapacity = hp->_capacity == 0 ? 4 : 2 * hp->_capacity;
		HPDataType* tmp = (HPDataType*)realloc(hp->_a, sizeof(HPDataType) * newcapacity);
		if (tmp == NULL)
		{
			perror("realloc fail");
			return;
		}
		hp->_a = tmp;
		hp->_capacity = newcapacity;
	}
	hp->_a[hp->_size] = x;
	AdjustUp(hp->_a, hp->_size);
	hp->_size++;
}
// 堆的删除
void HeapPop(Heap* hp)
{
	assert(hp);
	assert(hp->_size > 0);
	Swap(&hp->_a[0], &hp->_a[hp->_size - 1]);
	hp->_size--;
	AdjustDown(hp->_a, hp->_size, 0);
}
// 取堆顶的数据
HPDataType HeapTop(Heap* hp)
{
	assert(hp);
	assert(hp->_a);
	return hp->_a[0];
}
// 堆的数据个数
int HeapSize(Heap* hp)
{
	assert(hp);
	return hp->_size;
}
// 堆的判空
int HeapEmpty(Heap* hp)
{
	assert(hp);
	return hp->_size == 0;
}
teat,c(用于测试)
#define _CRT_SECURE_NO_WARNINGS 1
#include"Heap.h"

//int main()
//{
//	Heap* hp = (Heap*)malloc(sizeof(Heap));
//	int a[] = { 4,2,5,6,7,9 ,10,1,0,-1};
//	int size = sizeof(a) / sizeof(a[0]);
//	HeapCreate(hp, a, size);
//	while (!HeapEmpty(hp))
//	{
//		printf("size = %2d,pop %2d,\n",HeapSize(hp), HeapTop(hp));
//		HeapPop(hp);
//	}
//	printf("size =  0.exit\n");
//	return 0;
//}

//void CreateNDate()
//{
//	// 造数据1千万个
//	int n = 10000000;
//	srand(time(0));
//	const char* file = "data.txt";
//	FILE* fin = fopen(file, "w");
//	if (fin == NULL)
//	{
//		perror("fopen error");
//		return;
//	}
//
//	for (size_t i = 0; i < n; ++i)
//	{
//		int x = (rand() + i) % 10000000;
//		fprintf(fin, "%d\n", x);
//	}
//
//	fclose(fin);
//}
//void PrintTopK(const char* file, int k)
//{
//	FILE* fout = fopen(file, "r");
//	if (fout == NULL)
//	{
//		perror("fopen error");
//		return;
//	}
//	//建一个k个数的小堆
//	int* minheap = (int*)malloc(sizeof(int) * k);
//	if (minheap == NULL)
//	{
//		perror("malloc fail");
//		return;
//	}
//	for (int i = 0; i < k; i++)
//	{
//		fscanf(fout, "%d", &minheap[i]);
//		AdjustUp(minheap, i);
//	}
//
//	int x = 0;
//	while (fscanf(fout, "%d", &x) != EOF)
//	{
//		if (x > minheap[0])
//		{
//			minheap[0] = x;
//			AdjustDown(minheap, k, 0);
//		}
//	}
//	for (int i = 0; i < k; i++)
//	{
//		printf("%d ", minheap[i]);
//	}
//	fclose(fout);
//}
Top k 问题
//int main()
//{
//	//CreateNDate();
//	
//	PrintTopK("Data.txt", 5);
//	return 0;
//}

// 对数组进行堆排序
void swap(int* a, int* b)
{
	int temp = *a;
	*a = *b;
	*b = temp;
}

void HeapSort(int* a, int n)
{
	for (int i = (n - 1) / 2; i >= 0; i--)
	{
		AdjustDown(a, n, i);
	}

	int end = n - 1;
	while (end > 0)
	{
		swap(&a[0], &a[end]);
		AdjustDown(a, end, 0);
		end--;
	}
}

int main()
{
	int a[9] = { 50,10,90, 30, 70, 40, 80, 60, 20 };
	HeapSort(a, 9);
	for (int i = 0; i < 9; i++)
	{
		printf("%d ", a[i]);
	}
	return 0;
}

4.二叉树链式结构的实现

4.1二叉树的遍历

4.1.1 前序、中序以及后序遍历

学习二叉树结构,最简单的方式就是遍历。所谓 二叉树遍历 (Traversal) 是按照某种特定的规则,依次对二叉 树中的节点进行相应的操作,并且每个节点只操作一次 。访问结点所做的操作依赖于具体的应用问题。 遍历是二叉树上最重要的运算之一,也是二叉树上进行其它运算的基础。
按照规则,二叉树的遍历有: 前序 / 中序 / 后序的递归结构遍历
1. 前序遍历 (Preorder Traversal 亦称先序遍历 )—— 访问根结点的操作发生在遍历其左右子树之前。
2. 中序遍历 (Inorder Traversal)—— 访问根结点的操作发生在遍历其左右子树之中(间)。
3. 后序遍历 (Postorder Traversal)—— 访问根结点的操作发生在遍历其左右子树之后。
由于被访问的结点必是某子树的根, 所以 N(Node )、 L(Left subtree )和 R(Right subtree )又可解释为 根、根的左子树和根的右子树 NLR LNR LRN 分别又称为先根遍历、中根遍历和后根遍历。
// 二叉树前序遍历
void PreOrder(BTNode* root);
// 二叉树中序遍历
void InOrder(BTNode* root);
// 二叉树后序遍历
void PostOrder(BTNode* root);

4.1.2 层序遍历

层序遍历 :除了先序遍历、中序遍历、后序遍历外,还可以对二叉树进行层序遍历。设二叉树的根节点所在层数为1 ,层序遍历就是从所在二叉树的根节点出发,首先访问第一层的树根节点,然后从左到右访问第 2 层上的节点,接着是第三层的节点,以此类推,自上而下,自左至右逐层访问树的结点的过程就是层序遍历。
层序遍历会用到队列,所以在后边的二叉树代码实现中我会将队列的相关代码也一并放入

4.2 节点个数以及高度等

// 二叉树节点个数
int BinaryTreeSize(BTNode* root);
// 二叉树叶子节点个数
int BinaryTreeLeafSize(BTNode* root);
// 二叉树第k层节点个数
int BinaryTreeLevelKSize(BTNode* root, int k);
// 二叉树查找值为x的节点
BTNode* BinaryTreeFind(BTNode* root, BTDataType x);

4.3 二叉树的代码实现

BinaryTree.h

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

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

//创建一个二叉树节点
BTNode* BinaryTreeBuyNode(BTDataType x);
//通过前序遍历的数组"A B D # # E # H # # C F # # G # #"构建二叉树
BTNode* BinaryTreeCreate();
BTNode* CreateTree(BTDataType* a, 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);

Queue.h

#pragma once
#include"BinaryTree.h"
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
#include<stdbool.h>
typedef struct BinaryTreeNode* QDataType;
// 链式结构:表示队列 
typedef struct QListNode
{
	struct QListNode* _next;
	QDataType _data;
}QNode;

// 队列的结构 
typedef struct Queue
{
	QNode* _front;
	QNode* _rear;
}Queue;

// 初始化队列 
void QueueInit(Queue* q);
// 队尾入队列 
void QueuePush(Queue* q, QDataType data);
// 队头出队列 
void QueuePop(Queue* q);
// 获取队列头部元素 
QDataType QueueFront(Queue* q);
// 获取队列队尾元素 
QDataType QueueBack(Queue* q);
// 获取队列中有效元素个数 
int QueueSize(Queue* q);
// 检测队列是否为空,如果为空返回非零结果,如果非空返回0 
int QueueEmpty(Queue* q);
// 销毁队列 
void QueueDestroy(Queue* q);

BinaryTree.c

#include"BinaryTree.h"
#include"Queue.h"

//创建一个二叉树节点
BTNode* BinaryTreeBuyNode(BTDataType x)
{
	BTNode* newnode = (BTNode*)malloc(sizeof(BTNode));
	if (newnode == NULL)
	{
		perror("malloc fail:");
		return NULL;
	}
	newnode->_data = x;
	newnode->_left = newnode->_right = NULL;
	return newnode;
}
//通过前序遍历的数组"A B D # # E # H # # C F # # G # #"构建二叉树
//BTNode* BinaryTreeCreate()
//{
//	BTNode* node1 = BinaryTreeBuyNode('A');
//	BTNode* node2 = BinaryTreeBuyNode('B');
//	BTNode* node3 = BinaryTreeBuyNode('C');
//	BTNode* node4 = BinaryTreeBuyNode('D');
//	BTNode* node5 = BinaryTreeBuyNode('E');
//	BTNode* node6 = BinaryTreeBuyNode('F');
//	BTNode* node7 = BinaryTreeBuyNode('G');
//	BTNode* node8 = BinaryTreeBuyNode('H');
//
//	node1->_left = node2;
//	node1->_right = node3;
//	node2->_left = node4;
//	node2->_right = node5;
//	node3->_left = node6;
//	node3->_right = node7;
//	node5->_right = node8;
//	return node1;
//}
BTNode* CreateTree(BTDataType* a, int* pi) {
	if (a[*pi] == '#')
	{
		(*pi)++;
		return NULL;
	}
	BTNode* root = (BTNode*)malloc(sizeof(BTNode));
	root->_data = a[(*pi)++];
	root->_left = CreateTree(a, pi);
	root->_right = CreateTree(a, pi);
	return root;
}
// 二叉树销毁
void BinaryTreeDestory(BTNode** root)
{
	if (root == NULL || *root == NULL)
	{
		return;
	}
	BinaryTreeDestory(&((*root)->_left));
	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 == NULL && root->_right == NULL)
	{
		return 1;
	}
	return BinaryTreeLeafSize(root->_left) + BinaryTreeLeafSize(root->_right);
}
// 二叉树第k层节点个数
int BinaryTreeLevelKSize(BTNode* root, int k)
{
	if (root == NULL || k < 1)
	{
		return 0;
	}
	if (k == 1)
	{
		return 1;
	}
	return BinaryTreeLevelKSize(root->_left,k-1) + BinaryTreeLevelKSize(root->_right,k-1);
}
// 二叉树查找值为x的节点
BTNode* BinaryTreeFind(BTNode* root, BTDataType x)
{
	if (root == NULL)
	{
		return NULL;
	}
	if (root->_data == x)
	{
		return root;
	}
	BTNode* leftnode = BinaryTreeFind(root->_left,x);
	BTNode* rightnode = BinaryTreeFind(root->_right,x);
	if (leftnode != NULL)
	{
		return leftnode;
	}
	if (rightnode != NULL)
	{
		return rightnode;
	}
	return NULL;
}
// 二叉树前序遍历 
void BinaryTreePrevOrder(BTNode* root)
{
	if (root == NULL)
	{
		printf("# ");
		return;
	}
	printf("%c ", root->_data);
	BinaryTreePrevOrder(root->_left);
	BinaryTreePrevOrder(root->_right);
}
//另一种前序遍历
//
// Definition for a binary tree node.
//  struct TreeNode {
//      int val;
//      struct TreeNode *left;
//      struct TreeNode *right;
// };
// 
//
// Note: The returned array must be malloced, assume caller calls free().
// 
//int TreeSize(struct TreeNode* root)
//{
//    if(root == NULL)
//    {
//        return 0;
//    }
//    return TreeSize(root->left) + TreeSize(root->right) + 1;
//}
//void preorder(struct TreeNode* root,int* a,int* pi)
//{
//    if(root == NULL)
//    {
//        return;
//    }
//    a[(*pi)++] = root->val;
//    preorder(root->left,a,pi);
//    preorder(root->right,a,pi);
//}
//int* preorderTraversal(struct TreeNode* root, int* returnSize) {
//    int n = TreeSize(root);
//    *returnSize = n;
//    int* a = (int*)malloc(sizeof(int) * n);
//    if(a == NULL)
//    {
//        perror("malloc fail:");
//        return NULL;
//    }
//    int i = 0;
//    preorder(root,a,&i);
//    return a;
//}
// 二叉树中序遍历
void BinaryTreeInOrder(BTNode* root)
{
	if (root == NULL)
	{
		printf("# ");
		return;
	}
	BinaryTreeInOrder(root->_left);
	printf("%c ", root->_data);
	BinaryTreeInOrder(root->_right);
}
// 二叉树后序遍历
void BinaryTreePostOrder(BTNode* root)
{
	if (root == NULL)
	{
		printf("# ");
		return;
	}
	BinaryTreePostOrder(root->_left);
	BinaryTreePostOrder(root->_right);
	printf("%c ", root->_data);
}
// 层序遍历
void BinaryTreeLevelOrder(BTNode* root)
{
	if (root == NULL)
	{
		return;
	}
	Queue q;
	QueueInit(&q);
	int levelsize = 1;
	QueuePush(&q, root);
	while (!QueueEmpty(&q))
	{
		while (levelsize--)
		{
			BTNode* front = QueueFront(&q);
			QueuePop(&q);
			printf("%c ", front->_data);
			if (front->_left)
			{
				QueuePush(&q, front->_left);
			}
			if (front->_right)
			{
				QueuePush(&q, front->_right);
			}
		}
		printf("\n");
		levelsize = QueueSize(&q);
	}
	QueueDestroy(&q);
}
// 判断二叉树是否是完全二叉树,是返回1,不是返回0
int BinaryTreeComplete(BTNode* root)
{
	if (root == NULL)
	{
		return 1;
	}
	Queue q;
	QueueInit(&q);
	if (root)
	{
		QueuePush(&q, root);
	}
	while (!QueueEmpty(&q))
	{
		BTNode* front = QueueFront(&q);
		QueuePop(&q);
		if (front == NULL)
		{
			break;
		}
		QueuePush(&q, front->_left);
		QueuePush(&q, front->_right);
	}
	while (!QueueEmpty(&q)) 
	{
		BTNode* front = QueueFront(&q);
		QueuePop(&q);
		if (front)
		{
			QueueDestroy(&q);
			return 0;
		}
	}
	QueueDestroy(&q);
	return 1;
}

Queue.c

#include"Queue.h"
#include"BinaryTree.h"

// 初始化队列 
void QueueInit(Queue* q)
{
	assert(q);
	q->_front = q->_rear = NULL;
}
// 队尾入队列 
void QueuePush(Queue* q, QDataType data)
{
	assert(q);
	if (q->_rear == NULL)
	{
		q->_front = q->_rear = (QNode*)malloc(sizeof(QNode));
		if (q->_rear == NULL)
		{
			perror("q->_rear malloc");
			return;
		}
		q->_rear->_data = data;
		q->_rear->_next = NULL;
	}
	else
	{
		QNode* newnode = (QNode*)malloc(sizeof(QNode));
		if (newnode == NULL)
		{
			perror("newnode malloc");
			return;
		}
		newnode->_data = data;
		newnode->_next = NULL;
		q->_rear->_next = newnode;
		q->_rear = newnode;
	}
}
// 队头出队列 
void QueuePop(Queue* q)
{
	assert(q);
	assert(q->_front);
	QNode* del = q->_front;
	q->_front = q->_front->_next;
	if (q->_front == NULL)
	{
		q->_rear = NULL;
		return;
	}
	free(del);
	del = NULL;
}
// 获取队列头部元素 
QDataType QueueFront(Queue* q)
{
	assert(q);
	assert(q->_front);
	return q->_front->_data;
}
// 获取队列队尾元素 
QDataType QueueBack(Queue* q)
{
	assert(q);
	assert(q->_rear);
	return q->_rear->_data;
}
// 获取队列中有效元素个数 
int QueueSize(Queue* q)
{
	assert(q);
	int count = 0;
	QNode* cur = q->_front;
	while (cur)
	{
		count++;
		cur = cur->_next;
	}
	return count;
}
// 检测队列是否为空,如果为空返回非零结果,如果非空返回0 
int QueueEmpty(Queue* q)
{
	assert(q);
	if (q->_front == NULL)
	{
		return 1;
	}
	return 0;
}
// 销毁队列 
void QueueDestroy(Queue* q)
{
	assert(q);
	while (q->_front != NULL)
	{
		QNode* del = q->_front;
		q->_front = q->_front->_next;
		free(del);
	}
	q->_rear = NULL;
}

test.c(用于测试)

#include"BinaryTree.h"
#include"Queue.h"

int main()
{
	char* a = "ABD##E#H##CF##G##";
	char* b = "AB##C##";//一个完全二叉树,用来测试
	int i = 0;
	BTNode* ptree = CreateTree(a,&i);
	i = 0;
	BTNode* ptree2 = CreateTree(b, &i);
	printf("treesize = %d\n", BinaryTreeSize(ptree));
	printf("leafsize = %d\n", BinaryTreeLeafSize(ptree));
	int level = 4;
	printf("%dlevel's size = %d\n", level,BinaryTreeLevelKSize(ptree, level));
	printf("前序遍历:");
	BinaryTreePrevOrder(ptree);
	printf("\n");
	printf("中序遍历;");
	BinaryTreeInOrder(ptree);
	printf("\n");
	printf("后序遍历:");
	BinaryTreePostOrder(ptree);
	printf("\n层序遍历:\n");
	BinaryTreeLevelOrder(ptree);
	printf("tree1是否为完全二叉树?");//不是
	if (BinaryTreeComplete(ptree) == 0)
	{
		printf("不是\n");
	}
	else
	{
		printf("是\n");
	}	
	printf("tree2是否为完全二叉树?");//是
	if (BinaryTreeComplete(ptree2) == 0)
	{
		printf("不是\n");
	}
	else
	{
		printf("是\n");
	}
	char x = 'H';
	printf("\n寻找节点%c,", x);
	BTNode* findnode = BinaryTreeFind(ptree, x);
	if (findnode != NULL)
	{
		printf("所寻找的节点数据域为%c\n", findnode->_data);
	}
	else
	{
		printf("没有找到该节点\n");
	}
	
	BinaryTreeDestory(&ptree); 
	printf("\n销毁后:");
	BinaryTreePrevOrder(ptree);
	return 0;
}

测试截图

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值