目录
一 树的概念及结构
1.1树的概念及结构
树是一种非线性的数据结构,它是由n(n>=0)个有限结点组成一个具有层次关系的集合。把它叫做树是因为它看起来像一棵倒挂的树,也就是说它是根朝上,而叶朝下的。
节点的度:一个节点含有的子树的个数称为该节点的度; 如下图: A 的为 6叶节点或终端节点:度为 0 的节点称为叶节点; 如下图: B 、 C 、 H 、 I... 等节点为叶节点非终端节点或分支节点:度不为 0 的节点; 如下图: D 、 E 、 F 、 G... 等节点为分支节点双亲节点或父节点:若一个节点含有子节点,则这个节点称为其子节点的父节点; 如下图: A 是 B的父节点孩子节点或子节点:一个节点含有的子树的根节点称为该节点的子节点; 如下图: B 是 A 的孩子节点兄弟节点:具有相同父节点的节点互称为兄弟节点; 如下图: B 、 C 是兄弟节点树的度:一棵树中,最大的节点的度称为树的度; 如下图:树的度为 6节点的层次:从根开始定义起,根为第 1 层,根的子节点为第 2 层,以此类推;树的高度或深度:树中节点的最大层次; 如下图:树的高度为 4(根默认为1,也可以默认为0)节点的祖先:从根到该节点所经分支上的所有节点;如下图: A 是所有节点的祖先森林:由 m ( m>0 )棵互不相交的多颗树的集合称为森林;(数据结构中的学习并查集本质就是一个森林)![]()
1.2树的表示
树结构相对线性表就比较复杂了,要存储表示起来就比较麻烦了,实际中树有很多种表示方式, 如:双亲表示法,孩子表示法、孩子兄弟表示法等等。我们这里就简单的了解其中最常用的孩子 兄弟表示法 。![]()
二 二叉树的概念及结构
2.1基本概念
一棵二叉树是结点的一个有限集合,该集合或者为空,或者是由一个根节点加上两棵别称为左子 树和右子树的二叉树组成。 (度不超过2的树)二叉树的特点:1. 每个结点最多有两棵子树,即二叉树不存在度大于 2 的结点。2. 二叉树的子树有左右之分,其子树的次序不能颠倒。2.2特殊的二叉树
![]()
2.3二叉树性质
1. 若规定根节点的层数为 1 ,则一棵非空二叉树的 第 i 层上最多有 2^(i-1) 个结点 .2. 若规定根节点的层数为 1 ,则 深度为 h 的二叉树的最大结点数是 2^h- 1 .3. 对任何一棵二叉树 , 如果度为 0 其叶结点个数为 n0, 度为 2 的分支结点个数为 n2则有 n0 = n2 + 14. 若规定根节点的层数为 1 ,具有 n 个结点的满二叉树的深度 , h=LogN(由于格式问题具体见下图解)![]()
2.4二叉树性质练习题
2.5顺序存储
顺序结构存储就是使用 数组来存储 ,一般使用数组 只适合表示完全二叉树 ,因为不是完全二叉树会有空间的浪费。而现实中使用中只有堆才会使用数组来存储。二叉树顺序存储在物理上是一个数组,在逻辑上是一颗二叉树。
三 二叉树遍历
1 二叉树前中后序遍历
1.1基本概念
所谓遍历 (Traversal) 是指沿着某条搜索路线, 依次对树中每个结点均做一次且仅做一次访问 。访问结点所做的操作依赖于具体的应用问题。遍历是二叉树上最重要的运算之一,是二叉树上进行其它运算之基础。前序 / 中序 / 后序的递归结构遍历 :是根据访问结点操作发生位置命名1. NLR :前序遍历 (Preorder Traversal 亦称先序遍历 )—— 访问根结点的操作发生在遍历其左右(根 左子树 右子树)子树之前。2. LNR :中序遍历 (Inorder Traversal)—— 访问根结点的操作发生在遍历其左右子树之中(左子树 根 右子树)。3. LRN :后序遍历 (Postorder Traversal)—— 访问根结点的操作发生在遍历其左右子树之后。(左子树 右子树 根)由于被访问的结点必是某子树的根, 所以 N(Node )、 L(Left subtree )和 R(Right subtree )又 可解释为根、根的左子树和根的右子树 。 NLR 、 LNR 和 LRN 分别又称为先根遍历、中根遍历和后根遍历。![]()
1.2前中后序代码实现
//前序 void PrevOrder(Tree*root) { if (root == NULL) { return; } printf("%c ",root->data); PrevOrder(root->left); PrevOrder(root->right); } //中序 void InOrder(Tree* root) { if (root == NULL) { return; } InOrder(root->left); printf("%c ", root->data); InOrder(root->right); } //后序 void PostOrder(Tree* root) { if (root == NULL) { return; } PostOrder(root->left); PostOrder(root->right); printf("%c ", root->data); }
1.3递归画图理解
2 层序遍历
2.1基本思想
层序遍历是利用队列的结构特点实现的
2.2代码实现
//层序遍历 void LevelOrder(Tree* root) { Queue q; QueueInit(&q); if (root) QueuePush(&q, root); while (!QueueEmpty(&q)) { Tree* Front = QueueFront(&q); QueuePop(&q); printf("%c ", Front->data); if (Front->left) QueuePush(&q, Front->left); if (Front->right) QueuePush(&q, Front->right); } printf("\n"); QueueDestory(&q); }
3 节点个数
3.1代码实现
//第一种 //使用全局变量 //缺点在多线程中同时计算两棵树的时候会有问题 int size1 = 0; void TreeSize1(Tree* root) { if (root == NULL) return; size1++; TreeSize1(root->left); TreeSize1(root->right); } //第二种 //传地址 void TreeSize2(Tree* root,int* psize) { if (root == NULL) return; (*psize)++; TreeSize2(root->left,psize); TreeSize2(root->right,psize); } //第三种 //分治思想 int TreeSize3(Tree* root) { return root == NULL ? 0 : TreeSize3(root->left) + TreeSize3(root->right) + 1; }
4 叶子节点个数
4.1代码实现
// 叶子节点的个数 int TreeLeafSize(Tree* root) { if (root == NULL) return 0; if (root->left == NULL && root->right == NULL) return 1; return TreeLeafSize(root->left)+TreeLeafSize(root->right); }