[数据结构]二叉树的链式存储结构

目录

二叉树的链式存储结构::

                                            1.创建一颗二叉树

                                            2.二叉搜索树简介

                                            3.前序、中序以及后序遍历

                                            4.层序遍历

                                            5.求一棵树的节点个数代码实现

                                            6.求一棵树的高度代码实现

                                            7.求叶子节点个数代码实现

                                            8.求第K层节点个数代码实现

                                            9.二叉树查找值为x的节点


二叉树的链式存储结构::

1.创建一颗二叉树

#include
#include
#include
#include
typedef int BTDataType;
typedef struct BinaryTreeNode
{
	BTDataType data;
	struct BinaryTreeNode* left;
	struct BinaryTreeNode* right;
}BTNode;
BTNode* CreateTree()
{
	BTNode* n1 = (BTNode*)malloc(sizeof(BTNode));
	assert(n1);
	BTNode* n2 = (BTNode*)malloc(sizeof(BTNode));
	assert(n2);
	BTNode* n3 = (BTNode*)malloc(sizeof(BTNode));
	assert(n3);
	BTNode* n4 = (BTNode*)malloc(sizeof(BTNode));
	assert(n4);
	BTNode* n5 = (BTNode*)malloc(sizeof(BTNode));
	assert(n5);
	BTNode* n6 = (BTNode*)malloc(sizeof(BTNode));
	assert(n6);
	n1->data = 1;
	n2->data = 2;
	n3->data = 3;
	n4->data = 4;
	n5->data = 5;
	n6->data = 6;
	n1->left = n2;
	n1->right = n4;
	n2->left = n3;
	n2->right = NULL;
	n4->left = n5;
	n4->right = n6;
	n3->left = NULL;
	n3->right = NULL;
	n5->left = NULL;
	n5->right = NULL;
	n6->left = NULL;
	n6->right = NULL;
	return n1;
}

注意:上述代码并不是创建二叉树的方式,真正创建二叉树方式后续重点讲解。

2.二叉搜索树简介

二叉搜索树:
若它的左子树不为空,则左子树上的所有节点的值均小于它的根节点的值,若它的右子树不空,
则右子树上所有节点的值均大于它的根节点的值,它的左右子树也分别为二叉排序树,二叉搜索树
作为一种经典的数据结构,它既有链表的快速插入与删除操作的特点又有数组快速查找的优势,所以应用十分广泛,例如在文件系统和数据库系统一般会采用这种数据结构进行高效率的排序与检索操作,因此,二叉搜索树的增删查改才有意义,普通二叉树的增删查改价值不大。

[数据结构]二叉树的链式存储结构_第1张图片

 3.前序、中序以及后序遍历

学习二叉树结构,最简单的方式就是遍历,所谓二叉树遍历(Traversal)是按照某种特定的规则,依次对二叉树的节点进行相应的操作,并且每个节点只操作一次。访问节点所做的操作依赖于具体的应用问题。遍历是二叉树最重要的运算之一,也是二叉树上进行其他运算的基础。

[数据结构]二叉树的链式存储结构_第2张图片

按照规则,二叉树的遍历有:前序、中序、后序的递归结构遍历:
1.前序遍历(PreOrder Traversal 亦称先序遍历):访问根节点的操作发生在遍历其左右子树之前
2.中序遍历(InOrder Traversal):访问根节点的操作发生在遍历其左右子树之间
3.后序遍历(PostOrder Traversal):访问根节点的操作发生在遍历其左右子树之后

由于被访问的节点必是某子树的根,所以N(Node)、L(Left subtree)和R(Right subtree)又可解释为根、根的左子树、根的右子树。NLR、LNR、LRN分别又称为先根遍历、中根遍历和后根遍历。

[数据结构]二叉树的链式存储结构_第3张图片

二叉树的前序遍历:

typedef int BTDataType;
typedef struct BinaryTreeNode
{
	BTDataType data;
	struct BinaryTreeNode* left;
	struct BinaryTreeNode* right;
}BTNode;
void PreOrder(BTNode* root)
{
	if (root == NULL)
	{
		printf("NULL ");
		return;
	}
	printf("%d ", root->data);
	PreOrder(root->left);
	PreOrder(root->right);
}

前序遍历递归图解:

[数据结构]二叉树的链式存储结构_第4张图片

前序遍历递归展开图: 

[数据结构]二叉树的链式存储结构_第5张图片

 前序遍历结果:

[数据结构]二叉树的链式存储结构_第6张图片

二叉树的中序遍历: 

typedef int BTDataType;
typedef struct BinaryTreeNode
{
	BTDataType data;
	struct BinaryTreeNode* left;
	struct BinaryTreeNode* right;
}BTNode;
void InOrder(BTNode* root)
{
	if (root == NULL)
	{
		printf("NULL ");
		return;
	}
	InOrder(root->left);
	printf("%d ", root->data);
	InOrder(root->right);
}

中序遍历递归展开图:

[数据结构]二叉树的链式存储结构_第7张图片

中序遍历结果:

[数据结构]二叉树的链式存储结构_第8张图片

 二叉树的后序遍历: 

typedef int BTDataType;
typedef struct BinaryTreeNode
{
	BTDataType data;
	struct BinaryTreeNode* left;
	struct BinaryTreeNode* right;
}BTNode;
void PostOrder(BTNode* root)
{
	if (root == NULL)
	{
		printf("NULL ");
		return;
	}
	PostOrder(root->left);
	PostOrder(root->right);
	printf("%d ", root->data);
}

后序遍历递归展开图:

[数据结构]二叉树的链式存储结构_第9张图片后序遍历结果:3 2 5 6 4 1

[数据结构]二叉树的链式存储结构_第10张图片4.层序遍历

层序遍历 :除了先序遍历、中序遍历、后序遍历外,还可以对二叉树进行层序遍历。设二叉树的根节点所在
层数为 1 ,层序遍历就是从所在二叉树的根节点出发,首先访问第一层的树根节点,然后从左到右访问第 2
上的节点,接着是第三层的节点,以此类推,自上而下,自左至右逐层访问树的结点的过程就是层序遍历。
[数据结构]二叉树的链式存储结构_第11张图片
[数据结构]二叉树的链式存储结构_第12张图片
//层序遍历
typedef  BTNode* QDataType;
typedef struct QueueNode
{
	struct QueueNode* next;
	QDataType data;
}QNode;
//第三种不用二级指针的方式 封装成结构体
typedef struct Queue
{
	QNode* head;
	QNode* tail;
	int size;
}Queue;
void QueueInit(Queue* pq)
{
	assert(pq);
	pq->head = pq->tail = NULL;
	pq->size = 0;
}
bool QueueEmpty(Queue* pq)
{
	assert(pq);
	return pq->head == NULL && pq->tail == NULL;
}
void QueueDestory(Queue* pq)
{
	assert(pq);
	QNode* cur = pq->head;
	while (cur)
	{
		QNode* del = cur;
		cur = cur->next;
		free(del);
	}
	pq->head = pq->tail = NULL;
    pq->size = 0;
}
void QueuePush(Queue* pq, QDataType x)
{
	assert(pq);
	QNode* newnode = (QNode*)malloc(sizeof(QNode));
	if (newnode == NULL)
	{
		perror("malloc fail");
		exit(-1);
	}
	else
	{
		newnode->data = x;
		newnode->next = NULL;
	}
	if (pq->tail == NULL)
	{
		pq->head = pq->tail = newnode;
	}
	else
	{
		pq->tail->next = newnode;
		pq->tail = newnode;
	}
	pq->size++;
}
void QueuePop(Queue* pq)
{
	assert(pq);
	assert(!QueueEmpty(pq));
	if (pq->head->next == NULL)
	{
		free(pq->head);
		pq->head = pq->tail = NULL;
	}
	else
	{
		QNode* del = pq->head;
		pq->head = pq->head->next;
		free(del);
		del = NULL;
	}
	pq->size--;
}
//取队列头部数据
QDataType QueueFront(Queue* pq)
{
	assert(pq);
	assert(!QueueEmpty(pq));
	return pq->head->data;
}
//取队列尾部数据
QDataType QueueBack(Queue* pq)
{
	assert(pq);
	assert(!QueueEmpty(pq));
	return pq->tail->data;
}
int QueueSize(Queue* pq)
{
	assert(pq);
	return pq->size;
}
void TreelevelOrder(BTNode* root)
{
	Queue q;
	QueueInit(&q);
	if (root)
		QueuePush(&q, root);
	while (!QueueEmpty(&q))
	{
		//取队头数据 这里队列中的数据是树的节点的指针,类型为BTNode*
		BTNode* front = QueueFront(&q);
		QueuePop(&q);
		printf("%d ", front->data);
		//下一层入队列的前提条件是 front->left不为空
		if (front->left)
			QueuePush(&q, front->left);
		//下一层入队列的前提条件是 front->right不为空
		if (front->right)
			QueuePush(&q, front->right);
	}
	printf("\n");
	QueueDestory(&q);
}

[数据结构]二叉树的链式存储结构_第13张图片

[数据结构]二叉树的链式存储结构_第14张图片

选择题练习:

1.某完全二叉树按层次输出(同一层从左到右)的序列为 ABCDEFGH 。该完全二叉树的前序序列为()
A ABDHECFG
B ABCDEFGH
C HDBEAFCG
D HDEBFGCA
2.二叉树的先序遍历和中序遍历如下:先序遍历:EFHIGJK;中序遍历:HFIEJKG.则二叉树根结点为()
A E
B F
C G
D H
3.设一课二叉树的中序遍历序列:badce,后序遍历序列:bdeca,则二叉树前序遍历序列为____。
A adbce
B decab
C debac
D abcde
4.某二叉树的后序遍历序列与中序遍历序列相同,均为 ABCDEF ,则按层次输出(同一层从左到右)的序列为
A FEDCBA    
B CBAFED
C DEFCBA
D ABCDEF
答案:
A
A
D
A

[数据结构]二叉树的链式存储结构_第15张图片

 [数据结构]二叉树的链式存储结构_第16张图片

 [数据结构]二叉树的链式存储结构_第17张图片

 [数据结构]二叉树的链式存储结构_第18张图片

5.求一棵树的节点个数代码实现

[数据结构]二叉树的链式存储结构_第19张图片

[数据结构]二叉树的链式存储结构_第20张图片

[数据结构]二叉树的链式存储结构_第21张图片

//切分子问题思路解决
int TreeSize(BTNode * root)
{
	if (root == NULL)
	{
		return 0;
	}
	else
	{
		return TreeSize(root->left) + TreeSize(root->right) + 1;
	}
}
int main()
{
	BTNode* root = CreateTree();
	int count = TreeSize(root);
	printf("Tree Size:%d\n", count);
	return 0;
}

[数据结构]二叉树的链式存储结构_第22张图片

切分子问题思路递归图解:

[数据结构]二叉树的链式存储结构_第23张图片

 切分子问题递归展开图:

[数据结构]二叉树的链式存储结构_第24张图片

6.求一棵树的高度代码实现

[数据结构]二叉树的链式存储结构_第25张图片

//求树的高度
//父亲的高度 = 左右子树的高度大的 + 1
int TreeHeight(BTNode* root)
{
	if (root == NULL)
	{
		return 0;
	}
	int leftHeight = TreeHeight(root->left);
	int rightHeight = TreeHeight(root->right);
	return leftHeight > rightHeight ? leftHeight + 1 : rightHeight + 1;
}

[数据结构]二叉树的链式存储结构_第26张图片

[数据结构]二叉树的链式存储结构_第27张图片

切分子问题思路递归图解:

[数据结构]二叉树的链式存储结构_第28张图片

7.求叶子节点个数代码实现

[数据结构]二叉树的链式存储结构_第29张图片

//求叶子节点的个数
int TreeLeafSize(BTNode* root)
{
	if (root == NULL)
	{
		return 0;
	}
	if (root->left == NULL && root->right == NULL)
	{
		return 1;
	}
	return TreeLeafSize(root->left) + TreeLeafSize(root->right);

}

[数据结构]二叉树的链式存储结构_第30张图片

切分子问题思路递归图解:

[数据结构]二叉树的链式存储结构_第31张图片

 切分子问题递归展开图:

[数据结构]二叉树的链式存储结构_第32张图片

8.求第K层节点个数代码实现

[数据结构]二叉树的链式存储结构_第33张图片

int TreeKLevel(BTNode* root, int k)
{
	assert(k > 0);
	if (root == NULL)
	{
		return 0;
	}
	if (k == 1)
	{
		return 1;
	}
	return TreeKLevel(root->left, k - 1) + TreeKLevel(root->right, k - 1);
}

[数据结构]二叉树的链式存储结构_第34张图片

 切分子问题思路递归图解:

[数据结构]二叉树的链式存储结构_第35张图片

 切分子问题递归展开图:

[数据结构]二叉树的链式存储结构_第36张图片

9.二叉树查找值为x的节点

[数据结构]二叉树的链式存储结构_第37张图片

//返回x所在的节点
//该代码是一个前序查找的过程
typedef int BTDataType;
typedef struct BinaryTreeNode
{
	BTDataType data;
	struct BinaryTreeNode* left;
	struct BinaryTreeNode* right;
}BTNode;
BTNode* TreeFind(BTNode* root, BTDataType x)
{
	if (root == NULL)
	{
		return NULL;
	}
	if (root->data == x)
	{
		return root;
	}
	//一定要用返回值接收递归的结果 不然就要递归调用一次自己
	BTNode* leftRet = TreeFind(root->left, x);
	//先去左树找 找到了就返回
	if (leftRet != NULL)
	{
		return leftRet;
	}
	//左树没有找到再到右树找
	BTNode* rightRet = TreeFind(root->right, x);
	if (rightRet != NULL)
	{
		return rightRet;
	}
	return NULL;
}

[数据结构]二叉树的链式存储结构_第38张图片

切分子问题思路递归图解: 

[数据结构]二叉树的链式存储结构_第39张图片

切分子问题思路递归展开图: 

[数据结构]二叉树的链式存储结构_第40张图片

深度优先遍历和广度优先遍历简介:

[数据结构]二叉树的链式存储结构_第41张图片

 

你可能感兴趣的:(数据结构)