目录
二叉树的链式存储结构::
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.层序遍历
![](https://i-blog.csdnimg.cn/blog_migrate/059a8e6c37e6e08b14fc5bcbde213c77.png)
![](https://i-blog.csdnimg.cn/blog_migrate/1a82e3ad64d8f6c7670eaa7e83db3831.png)
//层序遍历
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;
}
切分子问题思路递归图解:
切分子问题思路递归展开图:
深度优先遍历和广度优先遍历简介: