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

目录

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

                                            1.创建一颗二叉树

                                            2.二叉搜索树简介

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

                                            4.层序遍历

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

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

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

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

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


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

1.创建一颗二叉树

#include<stdio.h>
#include<assert.h>
#include<stdlib.h>
#include<stdbool.h>
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.二叉搜索树简介

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

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

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

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

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

二叉树的前序遍历:

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);
}

前序遍历递归图解:

前序遍历递归展开图: 

 前序遍历结果:

二叉树的中序遍历: 

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);
}

中序遍历递归展开图:

中序遍历结果:

 二叉树的后序遍历: 

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);
}

后序遍历递归展开图:

后序遍历结果:3 2 5 6 4 1

4.层序遍历

层序遍历 :除了先序遍历、中序遍历、后序遍历外,还可以对二叉树进行层序遍历。设二叉树的根节点所在
层数为 1 ,层序遍历就是从所在二叉树的根节点出发,首先访问第一层的树根节点,然后从左到右访问第 2
上的节点,接着是第三层的节点,以此类推,自上而下,自左至右逐层访问树的结点的过程就是层序遍历。
//层序遍历
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);
}

选择题练习:

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

 

 

 

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

//切分子问题思路解决
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;
}

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

 切分子问题递归展开图:

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

//求树的高度
//父亲的高度 = 左右子树的高度大的 + 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;
}

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

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

//求叶子节点的个数
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);

}

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

 切分子问题递归展开图:

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

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);
}

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

 切分子问题递归展开图:

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

//返回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;
}

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

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

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

 

  • 11
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值