赞
踩
目录
树是一种非线性的数据结构,它是由n个有限节点组成的具有层次关系的集合。每一个节点代表一个元素,由父节点和子节点的层次关系连接。它被叫做树的原因是因为看起来像一颗倒挂的树(根朝上,叶子朝下)。
所以树都是递归定义的。
在树形结构中,子树之间不能有交集,否则就不是树形结构。
树结构的表示相较于线性表就比较麻烦,因为既要保存值域,也要保存节点和节点的关系。
树常用的表示方法有:
节点链接表示
数组表示
双亲表示
孩子-兄弟表示
我们了解下最常用的孩子兄弟表示法。
- typedef int DataType;
- struct Node
- {
- struct Node* firstChild1;
- struct Node* pNextBrother;
- DataType data;
- };
这种表示法的优势在于便于插入删除节点(修改指针即可)、方便遍历所有节点、适用于表示有多个孩子或需要频繁变更结构的树
除此之外,树还可以用于文件系统、组织结构图、数据库索引和优先队列和堆等等。
在一棵树中,每个节点最多只有两个子节点(通常称为左节点和右节点),就是叫做二叉树。
任意二叉树都是有以下几种情况复合而成的。
满二叉树:所有层都是满的,即除了叶节点外,每个节点都有两个子节点。
完全二叉树:除去最后一层外,其他层的节点都是满的。(叶子节点那层可满可不满)满二叉树是一种特殊的完全二叉树。在最后一层,所有的节点都尽可能地集中在左侧连续排列。也就是说,如果最后一层不是满的,那么这些未填充的空位(如果存在)只能出现在右侧。
1.规定根节点的层数为1,一棵非空二叉树的第i层最多有2 ^ (i - 1)个节点。
最多是因为该层可能是最最后一层,不是满节点。
2.深度为h的二叉树的最大节点个数是2 ^ h - 1。
3.一棵二叉树,度为0的节点个数为n0,度为2的节点个数为n2,则n0 = n2 + 1。(度为0的节点比度为2节点多一个)
4.n个节点的满二叉树的深度h = log(n + 1)(以2为底)
1.顺序存储
顺序存储就是使用数组来存储,一般适合完全二叉树,如果不是的话会浪费空间,真正用数组存储的是堆(一种特殊的完全二叉树)。
二叉树顺序存储在物理上是一个数组,在逻辑上是一颗二叉树。
2.链式存储
链式存储就是用链表来表示一棵二叉树,每个节点由数据和左右指针构成。
- typedef int BTDataType;
-
- typedef struct BinarytreeNode
- {
- BTDataType data;
- struct BinaryTreeNode* left;
- struct BinaryTreeNode* right;
- }BTNode;
链式结构又分为二叉链和三叉链,我们先来学习用二叉链实现的树。
我们先要创建一棵二叉树,这样是为了便于后后序操作的进行。
注意:这不是真正的创建操作,这只是暴力创建一棵二叉树,是为了方便后续的学习与操作。
- typedef int BTDataType;
-
- typedef struct BinarytreeNode
- {
- BTDataType data;
- struct BinaryTreeNode* left;
- struct BinaryTreeNode* right;
- }BTNode;
-
- BTNode* BuyBTNode(BTDataType x)
- {
- BTNode* newnode = (BTNode*)malloc(sizeof(BTNode));
- if (newnode == NULL)
- {
- perror("malloc fail");
- return;
- }
- newnode->data = x;
- newnode->left = NULL;
- newnode->right = NULL;
- }
-
- BTNode* CreatBTNode()
- {
- BTNode* node1 = BuyBTNode(1);
- BTNode* node2 = BuyBTNode(2);
- BTNode* node3 = BuyBTNode(3);
- BTNode* node4 = BuyBTNode(4);
- BTNode* node5 = BuyBTNode(5);
- BTNode* node6 = BuyBTNode(6);
-
- node1->left = node2;
- node1->right = node4;
- node2->left = node3;
- node4->left = node5;
- node4->right = node6;
-
- return node1;
- }
二叉树的遍历是按照某种顺序访问树中的所有节点,而不需要改变树的结构。
二叉树的遍历方法有
访问顺序:根节点 -> 左子树 -> 右子树
首先访问根节点,然后递归前序遍历左子树,接着是右子树。
递归实现
- // 二叉树前序遍历
- void PrevOrder(BTNode* root)
- {
- if (root == NULL)
- {
- printf("N ");
- return;
- }
-
- printf("%d ", root->data);
- PrevOrder(root->left);
- PrevOrder(root->right);
- }
访问顺序:左子树 -> 右子树 -> 根节点。
首先递归进行中序遍历左子树,然后访问根节点,最后递归地进行中序遍历右子树。
递归实现
- // 二叉树中序遍历
- void InOrder(BTNode* root)
- {
- if (root == NULL)
- {
- printf("N ");
- return;
- }
- InOrder(root->left);
- printf("%d ", root->data);
- InOrder(root->right);
- }
访问顺序:左子树 -> 右子树 -> 根节点。
递归地进行后序遍历左子树,接着右子树,最后访问根节点。
递归实现
- //二叉树后序遍历
- void PostOrder(BTNode* root)
- {
- if (root == NULL)
- {
- printf("N ");
- return;
- }
- PostOrder(root->left);
- PostOrder(root->right);
- printf("%d ", root->data);
- }
二叉树的层序遍历,也称为广度优先遍历,按照从上到下、从左往右地顺序访问二叉树的节点。
这种遍历通常使用队列实现。
基本步骤:
- // 层序遍历
- void BinaryTreeLevelOrder(BTNode* root)
- {
- Queue q;
- QueueInit(&q);
- if (root)
- QueuePush(&q, root);
- while (!QueueEmpty(&q))
- {
- BTNode* front = QueueFront(&q);
- QueuePop(&q);
- printf("%d ", front->data);
-
- if (front->left)
- QueuePush(&q, front->left);
-
- if (front->right)
- QueuePush(&q, front->right);
- }
- QueueDestroy(&q);
- }
终止情况 节点为空则返回0。
单层递归处理逻辑 返回1 + 左子树节点的个数 + 右子树节点的个数
- // 二叉树节点个数
- int BinaryTreeSize(BTNode* root)
- {
- return root == NULL ? 0 :
- 1 + BinaryTreeSize(root->left) + BinaryTreeSize(root->right);
- }
这里把终止情况和在一起了。
终止情况 节点为空返回0;节点的左右子树为空返回1。
单层递归处理逻辑 返回左子树的叶子节点个数和右子树节点个数。
- // 二叉树叶子节点个数
- int BinaryTreeLeafSize(BTNode* root)
- {
- if (root == NULL) return 0;
-
- if (root && root->left == NULL && root->right == NULL) return 1;
-
- return BinaryTreeLeafSize(root->left) + BinaryTreeLeafSize(root->right);
- }
终止情况 节点为空返回0;节点的左右子树为空返回1。
单层递归处理逻辑 求出左子树和右子树的高度,比较一下,返回较大高度 + 1(加1是为了算上根节点)
- //二叉树高度
- int BinaryTreeHight(BTNode* root)
- {
- if (root == NULL) return 0;
-
- if (root && root->left == NULL && root->right == NULL) return 1;
-
- int lefthight = BinaryTreeHight(root->left);
- int righthight = BinaryTreeHight(root->right);
-
- return (lefthight > righthight ? lefthight : righthight) + 1;
- }
注意:这里左子树高度和右子树高度一定要存起来,不能直接放在return里,不然的话递归次数会指数级增加的
- (BinaryTreeHight(root->left) > BinaryTreeHight(root->right) ?
- BinaryTreeHight(root->left) : BinaryTreeHight(root->right)) + 1
上面这种写法是完全错误的写法,一定要避免。
终止情况 节点为空返回0;k == 1返回1。
单层递归处理逻辑 返回左子树k-1层节点的个数和右子树k-1层节点的个数。
- // 二叉树第k层节点个数
- int BinaryTreeLevelKSize(BTNode* root, int k) //左子树的k-1层,右子树的k-1层
- {
- if (root == NULL) 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* ret1 = BinaryTreeFind(root->left,x);
- if (ret1)
- return ret1;
- BTNode* ret2 = BinaryTreeFind(root->right, x);
- if (ret2)
- return ret2;
- return NULL;
- }
后序遍历的一个应用,递归访问左子树,然后右子树,销毁根节点。
- //二叉树销毁
- void BinaryTreeDestory(BTNode* root)
- {
- if (root == NULL)
- return;
-
- BinaryTreeDestory(root->left);
- BinaryTreeDestory(root->right);
- free(root);
- }
基本思想
将这棵树当成完全二叉树,将其节点(包括空节点)入队列,出队列时带入左右节点,当出队列访问到的节点为空时,不再入队列,然后遍历队列,发现有非空节点,说明不是完全二叉树,返回false,遍历完就返回true。
- bool BinaryTreeComplete(BTNode* root)
- {
- Queue q;
- QueueInit(&q);
- QueuePush(&q, root);
-
- while (!QueueEmpty(&q))
- {
- BTNode* front = QueueFront(&q);
- if (front == NULL)
- break;
- QueuePop(&q);
-
- QueuePush(&q, front->left);
-
- QueuePush(&q, front->right);
- }
-
- while (!QueueEmpty(&q))
- {
- BTNode* front = QueueFront(&q);
- if (front)
- return false;
- QueuePop(&q);
- }
- return true;
-
- }
给定一个前序遍历的数组,创建二叉树。
- // 通过前序遍历的数组"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 == NULL)
- {
- perror("malloc fail!");
- return NULL;
- }
- root->data = a[(*pi)++];
-
- root->left = BinaryTreeCreate(a, n, pi);
- root->right = BinaryTreeCreate(a, n, pi);
-
- return root;
- }
拜拜,下期再见
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。