DS第5章学习小结

一、树

  1. 结点——一个数据元素及若干指向子树的分支信息
  2. 结点的度——结点拥有的子树个数。
  3. 树的度——树中结点的最大度数
  4. 叶子结点——度为0的结点。
  5. 结点的层次——从根到该结点的层数(根结点为第1层)。
  6. 树的深度(或高度)——所有结点中最大的层数。
  7. 路径——树中两个结点之间所经过的结点序列。
  8. 路径长度——两结点之间路径上经过的边数。树中没有环,因此树中任意两个结点之间的路径都是唯一的。

线性结构

树形结构

第一个数据元素(无前驱)

根结点(无前驱)

最后一个数据元素(无后继)

多个叶子结点(无后继)

其他数据元素(一个前驱+一个后继)

其他数据元素(一个前驱+多个后继)

 

二、二叉树

 

类别

辨析

满二叉树

每一层都充满了结点,达到最大结点数

完全二叉树

除最后一层外,每一层都是满的,且最后一层结点从左向右出现

非完全二叉树

除最后一层外,每一层都是满的,最后一层结点不按从左向右出现

 

(一)  二叉树的性质

性质1:第i层的结点个数至多2^(i-1)   【若m叉树,则为m^(i-1)】

性质2:设深度为k,结点个数至多(2^k)-1

性质3:若叶子数为n0,度为2的结点数为n2,则n0=n2+1

             n=n0+n1+n2 ……①

             n=B(分支总数)+1 = n1+2n2+1 ……② // B = n0*0+n1*1+n2*2+……+nk*k

             n0=n2+1 ……③

性质4:n个结点的完全二叉树深度:(int)log2(n) + 1

性质5:完全二叉树从上至下,从左至右编号,对于编号为i的结点,左孩子编号必为2i,右孩子编号必为2i+1,双亲编号必为i/2(向下取整)

 

结点

叶子

分支

层数

深度

性质1

 

 

 

性质2

 

 

 

性质3

 

 

 

性质3

推导公式

 

 

性质4

 

 

 

性质5

 

 

 

 

 

(二)  二叉树/树的存储

1、 链式存储

 1 #define Maxsize 100
 2 typedef struct CNode
 3 {//孩子结点 
 4     int child;//孩子结点下标
 5     struct CNode *nextchild;
 6 }CNode;
 7   
 8 typedef struct
 9 {//每个结点
10     int parent;//父结点下标
11     char data;
12     CNode *firstchild;//孩子结点链表CNode头指针
13 }PNode;
14   
15 typedef struct
16 {//
17     PNode nodes[Maxsize];
18     int root;//根结点下标
19     int n;//树的结点数
20 }Tree; 
21   
22 /* 
23 typedef struct
24 {//树 
25     PNode *nodes;//在初始化时使用new来申请空间
26     int root;
27 }Tree;
28 Tree t;
29 t.nodes = new PNode[Maxsize];
30 */
带双亲的孩子链表

 

 

1 typedef struct CSNode
2 {
3     char data; //ElemType data;
4     struct CSNode *firstchild, *nextchild, *nextsibling;
5 }CSNode, *CSTree;
孩子兄弟表示法

2、 顺序存储

 

 1 #define Maxsize 100
 2 typedef struct
 3 {
 4     char data;
 5     int lch;
 6     int rch;
 7 }Node;
 8 
 9 typedef struct
10 {
11     Node data[Maxsize];
12     int root;//根结点编号 
13 }Tree;
孩子表示法

存储方式

结点下标

Data

Child下标

Child指针

Parent下标

链式存储

孩子链表

(此时以结构体形式存在,非下标值)

带双亲的孩子链表

顺序存储

双亲表示法

孩子表示法

双亲孩子表示法

(三)  二叉树的遍历

1、 先序遍历(根、左子树、右子树)注:递归思想,一定要等左子树遍历完,才能遍历右子树

1 void preorder(Btree T)
2 {
3     if(T)//if(T!=NULL)
4     {
5        cout<<T->data;
6        preorder(T->lchild);
7        preorder(T->rchild);
8     }
9 }
先序遍历

2、 中序遍历(左子树、根、右子树)

1 void inorder(Btree T)
2 {
3     if(T)
4     {
5        inorder(T->lchild);
6        cout<<T->data;
7        inorder(T->rchild);
8     }
9 }
中序遍历

3、 后序遍历(左子树、右子树、根)

1 void posorder(Btree T)
2 {
3     if(T)
4     {
5        posorder(T->lchild);
6        posorder(T->rchild);
7        cout<<T->data;
8     }
9 }
后序遍历

4、 层次遍历(从上到下,从左到右)

 1 bool Leveltraverse(Btree T)
 2 {
 3     Btree p;
 4     if(!T)
 5         return false;
 6     queue<Btree>Q; //创建一个普通队列(先进先出),里面存放指针类型
 7     Q.push(T); //根指针入队
 8     while(!Q.empty()) //如果队列不空
 9     {
10         p=Q.front();//取出队头元素作为当前扩展结点livenode
11         Q.pop(); //队头元素出队
12         cout<<p->data<<"  ";
13         if(p->lchild)
14             Q.push(p->lchild); //左孩子指针入队
15         if(p->rchild)
16             Q.push(p->rchild); //右孩子指针入队
17     }
18     return true;
19 }
层次遍历

三、哈夫曼树

思想:自底向上,让权值大的叶子离根近

方法:每次从树中选取没有双亲且权值最小的两棵树作为左、右子树,构造一棵新树,并将其插入原树,新树的根结点的权值为其左右孩子结点权值之和。

结论:1、哈夫曼树WPL值一定小于等于其他树

          2、哈夫曼树一定是最优二叉树,最优二叉树不一定是哈夫曼树

 

posted @ 2020-05-31 22:56  海底捞不动  阅读(221)  评论(0编辑  收藏  举报