赞
踩
- 有一个特殊的结点,称为根结点。
- 除根结点外,其余结点被分为M(M>0)个互不相交的集合T1、T2、T3......,其中每一个集合又是另外一棵结构与树类似的子树。每棵子树的根结点有且只有一个前驱,可以有0个或多个后继。
- 因此,树是递归定义的。
注意:树形结构中,子树之间不能有交集,否则就不是树形结构了!
- 节点的度:一个节点含有的子树的个数称为节点的度;如上图:A的为6
- 叶节点或终端节点:度为0的节点称为叶节点;如上图:B、C、H、I......等节点称叶节点
- 非终端节点或分支节点:度不为0的节点;如上图:D、E、F、G......等节点为分支节点
- 双亲节点或父节点:若一个节点含有子节点,则这个节点称为其子节点的父节点;如上图:A是B的父节点
- 子节点:一个节点含有的子树的根结点称为该节点的子节点;如上图:B是A的子节点
- 兄弟节点:具有相同父节点的节点称为兄弟节点;如上图:B和C是兄弟节点
- 树的度:一棵树中,最大的节点的度称为树的度;如上图,最大节点的度是A的度为6,因此树的度也是6
- 节点的层次:从根开始定义起,根为第1层,根的子节点为第2层,一次类推
- 树的高度或深度:树中节点的最大层次;如上图,树的高度为4
- 堂兄弟节点:双亲在同一层的节点互为堂兄弟
- 节点的祖先:从根到该节点所经分支上的所有节点;如上图:A是所有节点的祖先
- 子孙:以某节点为根的子树中任一节点都称为该节点的子孙
- 森林:由m(m>0)棵互不相交的树的集合称为森林
树结构相对线性表就比较复杂了,要存储表示起来就比较麻烦了, 既然保存值域,也要保存结点和结点之间 的关系 ,实际中树有很多种表示方式如:双亲表示法,孩子表示法、孩子双亲表示法以及孩子兄弟表示法等。
- typedef int DataType;
- struct Node
- {
- struct Node* _firstChild1; // 第一个孩子结点
- struct Node* _pNextBrother; // 指向其下一个兄弟结点
- DataType _data; // 结点中的数据域
- };
一个二叉树是节点的一个有限集合,该集合:
1、或者为空
2、由一个根节点加上两棵别称为左子树和右子树的二叉树组成
从上图可以看出:
1、二叉树不存在度大于2的节点
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; // 当前节点值域
- };
普通的二叉树是不适合用数组来存储的,因为可能会存在大量的空间浪费。而完全二叉树更适合使用顺序结构存储。现实中我们通常把堆 ( 一种二叉树 ) 使用顺序结构的数组来存储,需要注意的是这里的堆和操作系统 虚拟进程地址空间中的堆是两回事,一个是数据结构,一个是操作系统中管理内存的一块区域分段。
堆的性质:
- 堆中某个节点的值总是不大于或不小于其父节点的值;
- 堆总是一棵完全二叉树
- void HeapInit(Heap* hp)
- {
- assert(hp);
-
- hp->_a = NULL;
- hp->_capacity = 0;
- hp->_size = 0;
- }
- void HeapCreate(Heap* hp, HPDataType* a, int n)
- {
- hp->_a = (HPDataType*)malloc((n + 1) * sizeof(HPDataType));
- if (hp->_a == NULL)
- {
- perror("malloc fail");
- return;
- }
- hp->_capacity = n;
- hp->_size = 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 Swap(HPDataType* p1, HPDataType* p2)
- {
- HPDataType tmp = *p1;
- *p1 = *p2;
- *p2 = tmp;
- }
-
- // 向上调整
- void AdjustUp(HPDataType* a, int child)
- {
- int parent = (child - 1) / 2;
- while (child > 0)
- {
- if (a[child] > a[parent])
- {
- Swap(&a[child], &a[parent]);
- child = parent;
- parent = (child - 1) / 2;
- }
- else
- {
- break;
- }
- }
- }
- void AdjustDown(int* a, int n, int parent)
- {
- int child = parent * 2 + 1;
- while (child < n)
- {
- if (child + 1 < n && a[child + 1] < a[child])
- {
- child++;
- }
- if (a[parent] < a[child])
- {
- Swap(&a[parent], &a[child]);
- parent = child;
- child = parent * 2 + 1;
- }
- else
- {
- break;
- }
- }
- }
- void HeapPush(Heap* hp, HPDataType x)
- {
- assert(hp);
-
- if (hp->_size == hp->_capacity)
- {
- int newCapacity = hp->_capacity == 0 ? 4 : hp->_capacity * 2;
- HPDataType* tmp = (HPDataType*)realloc(hp->_a, newCapacity * sizeof(HPDataType));
- if (tmp == NULL)
- {
- perror("realloc fail");
- return;
- }
- hp->_a = tmp;
- hp->_capacity = newCapacity;
- }
-
- hp->_a[hp->_size] = x;
- hp->_size++;
- AdjustUp(hp->_a, hp->_size - 1);
- }
- void HeapPop(Heap* hp)
- {
- assert(hp);
- assert(!HeapEmpty(hp));
-
- Swap(&hp->_a[0], &hp->_a[hp->_size - 1]);
- hp->_size--;
- AdjustDown(hp->_a, hp->_size, 0);
- }
按照规则,二叉树的遍历有: 前序 / 中序 / 后序的递归结构遍历 :1. 前序遍历 (Preorder Traversal 亦称先序遍历 )—— 访问根结点的操作发生在遍历其左右子树之前。2. 中序遍历 (Inorder Traversal)—— 访问根结点的操作发生在遍历其左右子树之中(间)。3. 后序遍历 (Postorder Traversal)—— 访问根结点的操作发生在遍历其左右子树之后。
- //先序遍历 -- 根左右
- 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);
- }
层序遍历 :除了先序遍历、中序遍历、后序遍历外,还可以对二叉树进行层序遍历。设二叉树的根节点所在层数为1 ,层序遍历就是从所在二叉树的根节点出发,首先访问第一层的树根节点,然后从左到右访问第 2 层上的节点,接着是第三层的节点,以此类推,自上而下,自左至右逐层访问树的结点的过程就是层序遍历。
- // 层序遍历 -- 层序遍历(广度优先遍历)通常通过使用队列来实现,以保证按照从上到下、从左到右的顺序访问树的每个节点
- 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);
- }
-
- printf("\n");
-
- QueueDestroy(&q);
- }
- //二叉树节点个数
- int BTreeSize(BTNode* root)
- {
- if (root == NULL)
- {
- return 0;
- }
- return BTreeSize(root->left) + BTreeSize(root->right) + 1;
- }
- //求叶子节点的个数
- int BTreeLeafSize(BTNode* root)
- {
- if (root == NULL)
- {
- return 0;
- }
- if (root->left == NULL && root->right == NULL)
- {
- return 1;
- }
- return BTreeLeafSize(root->left) + BTreeLeafSize(root->right);
- }
- //求二叉树的高度
- int BTreeHeight(BTNode* root)
- {
- if (root == NULL)
- {
- return 0;
- }
- int LeftHeight = BTreeHeight(root->left);
- int RightHeight = BTreeHeight(root->right);
- return LeftHeight > RightHeight ? LeftHeight + 1 : RightHeight + 1;
- }
- //二叉树第k层节点的个数
- int BTreeLevelKSize(BTNode* root, int k)
- {
- assert(k > 0);
- if (root == NULL)
- {
- return 0;
- }
- if (k == 1)
- {
- return 1;
- }
- return BTreeLevelKSize(root->left, k - 1) + BTreeLevelKSize(root->right, k - 1);
- }
- //二叉树查找值为x的节点
- BTNode* BTreeFind(BTNode* root, BTDataType x)
- {
- if (root == NULL)
- return NULL;
- if (root->data == x)
- return root;
-
- BTNode* ret1 = BTreeFind(root->left, x);
- if (ret1)
- return ret1;
- BTNode* ret2 = BTreeFind(root->right, x);
- if (ret2)
- return ret2;
-
- return NULL;
- }
- int BinaryTreeComplete(BTNode* root)
- {
- if (!root) return 1;
-
- Queue q;
- QueueInit(&q, 10);
- QueuePush(&q, root);
- int mustBeLeaf = 0;
-
- while (!QueueEmpty(&q))
- {
- BTNode* node = QueuePop(&q);
-
- if (!node)
- {
- mustBeLeaf = 1;
- }
- else
- {
- if (mustBeLeaf)
- {
- QueueDestroy(&q);
- return 0;
- }
-
- QueuePush(&q, node->left);
- QueuePush(&q, node->right);
- }
- }
-
- QueueDestroy(&q);
- return 1;
- }
- // 二叉树销毁
- void BinaryTreeDestory(BTNode** root)
- {
- if (*root == NULL)
- return;
-
- BinaryTreeDestory((*root)->left);
- BinaryTreeDestory((*root)->right);
-
- free(*root);
- *root = NULL;
- }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。