6)赫夫曼树:赫夫曼压缩编码;
a.树的一个结点到另一个结点之间的分支构成两结点的路径,路径分支数目为路径长度;
树的路径长度:树根到每一个结点的路径长度之和;
b.结点带权路径长度:结点到树根之间路径长度与结点权的乘积;
树的带权路径长度:所有叶子结点带权路径长度和;
c.赫夫曼树:带权路径WPL最小的二叉树;
d.赫夫曼树构造:
有权值的叶子结点从小到大排成序列:A5,E10,B15,D30,C40;
取头两个最小权值的结点分别作为新结点N1的左右子节点,N1权值为5+10=15;
将N1、A、E插入有序序列:N1-15,B15,D30,C40;
重复以上步骤;
e.赫夫曼算法描述:
给定权值,构成二叉树,每棵二叉树有一个带权根结点左右子树为空;
F中选取权值最小的树构造新的二叉树,根结点权值为子树根结点权之和;
F中删除这两棵树,将新的二叉树加入F;
重复2和3,直到F只含一棵树;
f.赫夫曼编码:编码字符构造赫夫曼树,赫夫曼树左分支写0,右分支1;
七、图:
1.图:顶点vertex(数据元素)的集合(有穷非空)和顶点间边(顶点之间逻辑关系)的集合;
G(V,E),G为图,V是顶点集,E是边集;
2.无向边edge:两顶点间边无方向,用无序偶对表示;若任意顶点间无向边则为无向图;
有向边/弧arc:A弧头tail;D弧尾head;<A,D>为弧;都是有向边为有向图;
3.简单图:任意顶点间有边,但不重复出现;
无向完全图:任意两顶点间有边;(n*(n-1)/2条);
有向完全图:任意两顶点间有方向相反两条弧;(n*(n-1))
4.稀疏图:边或弧很少;反之为稠密图;
5.权weight:与图的边或弧相关的数;
网network:带权图;
6.无向图边的两顶点为邻接点adjacent,边依附incident于顶点;
顶点的度degree:和顶点相关联的边数;记为TD();
边数是各顶点度数和一半;;
7.有向图以顶点为头的弧数称为入度indegree,ID();
以顶点为尾的弧数为出度outdegree,OD();
TD=ID+OD;ID=OD;
8.路径path:顶点序列;(长度是路径上边或弧的数目);
简单路径:序列中顶点不重复出现;
回路/环cycle:第一个顶点到最后一个顶点相同的路径;
简单回路/简单环:除始末顶点,其余顶点不重复出现的回路;
9.连通图:任意两个顶点都是连通的无向图;
连通分量:无向图的极大连通子图;
强连通图:任意两顶点间存在路径的有向图;
强连通分量:有向图的极大强连通子图;
10.连通图生成树:极小的连通子图,含有图中n个顶点,但只有足以构成一棵树的n-1条边;
有向树:一个有向图恰有一个顶点入度为0,其余顶点入度为1;
有向图生成森林:若干棵有向树组成,含有全部顶点,但只有足以构成若干棵不想交有向树的弧;
11.ADT:
12.图的存储结构:
(1)邻接矩阵adjacency
matrix:两个数组:一维数组存储顶点,二维数组(邻接矩阵)存储边或弧;
无向图:
a.
由于无自己到自己的边,主对角线为0;无向图若无a-b就无b-a;即是一个对称矩阵;
b.
某顶点的度为它所在行/列元素之和;
有向图:
网:
由于权值有可能为0或负数,则用∞来代替不能连通位置的矩阵数值;
c.代码实现:
无向网:
构造顶点表;用∞初始化邻接矩阵;输入边的上下标和权值;
(2)邻接表adjacency
list:边数相对顶点较少则浪费存储空间;数组与链表相结合;
a.顶点用一维数组,每个数据元素存储指向第一个邻接点的指针;
b.每个顶点所有邻接点构成线性表;
无向图称顶点的边表:顶点表有data数据域和firstedge指针域;边表结点有advex存储与此结点邻接的点在顶点表中下标,指针域指向此节点下一个邻接点结点;
有向图称顶点作为弧尾的出边表;顶点表相同,边表中用出边的坐标填充数据域,指针域指向下一个;可构建逆邻接表;
带权值网图:在边表中在添加一个weight数据域;
c.
代码实现:
结构定义:
邻接表创建:
加粗部分为两次头插法;因为如果a-b是邻接点,则a的邻接表里就会有b,b 的同时也会有a;
创建邻接表结点,把临界序号赋给数据域,头插进去;
(3)十字链表:邻接表对于有向图只能研究入度和出度一者——把它们结合起来:十字链表;(有向优化)
a.顶点表:数据域data;指针域firstin入边表头指针,指向该顶点入边表第一个结点;指针域firstout指向该顶点出边表第一个结点;
边表:tailvex弧起点在顶点表下标;headvex弧终点在顶点表下标;headlink指入边表指针域,指向终点相同的下一条边;taillink出边表指针,指向同一起点的下一条边;
即邻接表不变,加入了逆邻接表(即加入表示了入边和头);
(4)邻接多重表:无向图中,如果主要对顶点进行操作则邻接表合适,但对边操作时,由于一个边需要在两个顶点的邻接表上标注,故操作边很麻烦,故用多重表来改善:(无向优化)
a.边表节点:ivex、jvex为顶点,ilink指向依附i的下一条边,jlink指向依附j的下一条边;;
b.即在多重表中,一条边只用一个结点表示;
(5)边集数组:两个一维数组;一个存储顶点信息,另一个存储边信息;
a.更关注边的信息;边数组由起点下标(begin),终点下标(end),权(weight)组成;
(见克鲁斯卡尔算法)
13.图的遍历:
(1)从图中某一顶点出发访问且只访问一次图中其余顶点;
(2)为了避免从出发到回到原点却仍有点没有遍历到的情况,应给访问过的顶点标记:设置访问数组visted[n],0未访问,1访问过了;
(3)深度优先遍历(深度优先搜索DFS):从某个顶点v出发,访问此顶点,从v的未被访问的邻接点出发深度优先遍历;
非连通图选未访问顶点为起点,选图中一个未曾访问的顶点作起点重复;
a.用邻接矩阵;i是起点,j是终点,用visited标识是否访问过(visited实际上就是顶点数组);
先初始化每个顶点为未访问;
按编号遍历每个顶点,未访问则调用DFS;
DFS打印出这个顶点的值,并把状态改为已访问;
再遍历,当终点未被访问且此边存在时,符合递归条件;用这个终点作为新的起点调用函数重复以上过程;
当终点都被访问过了后将跳出循环,j++直到找到未被访问到的顶点或者边不存在(非连通图才可能),函数调用,若为前情况则输出这个值;
此时所有顶点都被打印,且只打印一次;
b.用邻接表:前面的步骤一样,从进入打印顶点后不同;
其中gl包含顶点表和顶点数、边数;p为边表头指针,存在顶点域中;adjlist为顶点表;adjvex为边表中的数据域,存的是此顶点的邻接点再顶点域=数组的下标;
即如果点i未被访问,把i的顶点数据域(顶点值)打印;
将顶点的边表头指针赋给p;此时p指向边表的第一个结点;
当边表第一个结点不空(有邻接点)时,判断这个邻接点是否被访问过;
如果没有访问过,则重复以上步骤;
如果访问过则查看下一个邻接点;