数据结构与算法-哈夫曼树与图

数据结构与算法-哈夫曼树与图_第1张图片
“永远积极向上,永远豪情满怀,永远热泪盈眶!”


哈夫曼树与图

  • 1.哈夫曼树
    • 1.1树与二叉树的转换
    • 1.2森林与二叉树的转换
    • 1.3哈夫曼树
      • 1.3.1哈夫曼树的概念
      • 1.3.2哈夫曼树的构造
      • 1.3.3例题
  • 2.图
    • 2.1图的定义
    • 2.2图的基本术语
    • 2.3图的抽象数据类型
    • 2.4图的存储结构
      • 2.4.1邻接矩阵存储
        • ✅2.4.1.1邻接矩阵表示的类定义
        • ✅2.4.1.2创建图
        • ✅2.4.1.3定位操作-查找顶点信息在顶点数组中的下标
        • ✅2.4.1.4创建有向图或无向图
        • ✅2.4.1.5创建有向网或无向网
        • ✅2.4.1.6计算顶点的度数-有向图为例
        • ✅2.4.1.7以有向图为例

1.哈夫曼树

1.1树与二叉树的转换

由于二叉树和树均可以用二叉链表作为存储结构,因此以二叉链表为媒介可以倒数树和二叉树的对应关系。一棵树可以找到唯一的一棵二叉树与之对应。反之,一棵右子树为空的二叉树也可以转换成对应的树。

将一棵树转化为二叉树的方法如下:

  1. 加线:将树中所有相邻的兄弟之间加一条线。
  2. 抹线:保留树中每个结点与其第一个孩子结点之间的连线,删除它与其他孩子结点之间的连线。
  3. 旋转:以右侧有结点连线的结点为轴心,将其右侧结点顺时针旋转45°,使之成为一棵层次分明的二叉树。
    数据结构与算法-哈夫曼树与图_第2张图片

数据结构与算法-哈夫曼树与图_第3张图片

1.2森林与二叉树的转换

从树和二叉树的转换方式知,任何一棵树转换成二叉树,二叉树的右子树必为空。由此,我们可以把森林中的第二棵树的根结点看作第一棵树的根结点的兄弟,第三棵树的根结点看成是第二棵树的根结点的兄弟。
数据结构与算法-哈夫曼树与图_第4张图片

1.3哈夫曼树

1.3.1哈夫曼树的概念

哈夫曼树,又称最优二叉树,是一类树的带权路径长度最小的二叉树。

  • 路径:从一个祖先结点到子孙结点之间的分支构成这两个结点间的路径。
  • 路径长度:路径上分支的数目。
  • 树的路径长度:从根到每个结点的路径长度之和。
  • 结点的权:根据应用的需要可以给树的结点赋予权值。
  • 结点的带权路径长度:从根到该结点的路径长度与该结点权的乘法。
  • 树的带权路径长度:树中所有叶子结点的带权路径长度之和。
    带权路径长度最小的二叉树称为哈夫曼树,也称最优二叉树。

1.3.2哈夫曼树的构造

数据结构与算法-哈夫曼树与图_第5张图片

1.3.3例题

数据结构与算法-哈夫曼树与图_第6张图片
定理:对于具有n个叶子结点的哈夫曼树,共有2n-1个结点,其中有n-1个非叶子结点。

2.图

2.1图的定义

称有序二元组G=(V,E)是一个图,若其中V是一个非空有限集合(或称顶点集),V中的数据元素称为顶点,EV上的二元关系,称E为边集。
(1).若E中的顶点对(或序偶)(u,v)是无序的,则称G为无向图,称(u,v)G的一条无向边,显然,(u,v)(v,u)是指同一条边。
(2).若E中的顶点对(或序偶)(u,v)是有序的,则称G为有向图。称(u,v)G的一条有向边(或弧),其中,称u为弧尾(或始点),称v为弧头(或终点)。

2.2图的基本术语

  1. 端点、邻接点、自环和孤立点:在一个无向图G=(V,E)中,若e=(u,v)G中的一条边,uv称为边e的两个端点,称边e关联uv,也称u邻接v,或v邻接uuv称为边e=(u,v)的邻接点;若u=v,称(u,v)G的自环。对于任意的u属于V,若不存在任何边关联u,说明顶点u是孤立点。
  2. 完全图:令G=(V,E)为一个图,且|V|=n,|E|=m。若无向图中每两个顶点间都存在一条边,或在有向图中每两个顶点间都存在着方向相反的两条有向边,则称此图为完全图。显然,无向图包含n(n-1)/2条边,有向图包含n(n-1)条边。
  3. 稀疏图和稠密图:边数很少的图(m称为稀疏图,反之称为稠密图。
  4. 顶点的度、出度和入度:在无向图G=(V,E)中,对于每一个v属于V,称关联顶点v的边数为顶点v的度数,记为d(v).在有向图G=(V,E)中,对于每一个v属于V,称以v为始点的边的条数为v的出度,称以v为终点的边的条数为v的入度。在无向图中,顶点的度数之和与边数有如下关系:

在这里插入图片描述
在有向图中,顶点的度数之和与边数有如下关系:
在这里插入图片描述

  1. 子图、真子图和生成子图:G=(V,E),H=(V1,E1)是两个图。
    数据结构与算法-哈夫曼树与图_第7张图片

  2. 路径、路径长度、简单路径和初等路径:
    在这里插入图片描述

  3. 回路、简单回路和初等回路:
    在这里插入图片描述

  4. 连通、连通图和连通分量:
    数据结构与算法-哈夫曼树与图_第8张图片

  5. 连通、强连通和强连通分量:
    数据结构与算法-哈夫曼树与图_第9张图片

  6. 权和网:在某些图中,边或弧上具有与它相关的数据信息称之为权。在实际应用中,权值可以有某种含义。例如,在城市交通线路的图中,边上的权值可以来表示该线路上的长度或交通费用等。边上带权的图称为带权图,也称网。

  7. 生成树:包含Gn个顶点的极小连通子图称为图G的生成树。一棵具有n个顶点的生成树有且仅有n-1条边。


例题:图G=(V,E)是一个非连通无向图,共有36条边,则该图至少有多少个顶点?

该非连通无向图至少由一个顶点和一个连通无向图组成。(n-1)n/2=36,n=9,所以该图至少有10个顶点。

2.3图的抽象数据类型

ADT Graph{
    数据对象:
      D = V = {ai|1<=i<=n,ai属于Elemtype}
    数据关系:
      R = E = {(ai,aj)|1<=i<=n,1<=j<=n,ai,aj属于D}
    基本操作:
    InitGraph(&g,V,E);//初始化创建一个图
    DestroyGraph(&g);//摧毁图,释放图占用的存储空间
    LocateVex(g,v);//查找顶点v在图中的位置
    InsertVex(&g,v);//在图中插入一个顶点v
    DeleteVex(&g,v);//在图中删除一个顶点v
    Degree(g,v);//计算顶点v的度数
    DFETraverse(g,v);//从顶点v出发对图进行深度优先遍历
    BFSTraverse(g,v);//从顶点v出发对图进行广度优先遍历
    }ADT Graph

2.4图的存储结构

2.4.1邻接矩阵存储

数据结构与算法-哈夫曼树与图_第10张图片
数据结构与算法-哈夫曼树与图_第11张图片
图的邻接矩阵存储结构具有如下特点:

  1. 无向图的邻接矩阵是对称矩阵,实际存储时可以采用压缩矩阵存储。
  2. 有向图的邻接矩阵不一定对阵,因此,采用邻接矩阵存储具有n个顶点的有向图时,其存储结构的空复杂度为O(n2)。
  3. 无向图邻接矩阵的第i行(或第i列)中非0元素的个数,就是顶点i的度数。
  4. 有向图邻接矩阵的第i行中非0元素的个数,就是顶点i的出度,第i列中非0元素的个数,就是顶点i的入度。
  5. 利用邻接矩阵可以较容易地确定图中两顶点之间是否有边。但若要确实图的总边数,则要按行按列进行查询,耗费的时间代价较大。另外,邻接矩阵用数组表示时,静态数组的局限性不便于图的插入和删除操作,它们是邻接矩阵存储结构的局限性。
✅2.4.1.1邻接矩阵表示的类定义
#define _CRT_SECURE_NO_WARNINGS 1
#define MaxVex 20//预设最大顶点数
const int MAXINT = 0xfffffff;//最大整数,表示无穷大
typedef struct 
{
	VRType adj;//VRType为顶点关系类型,对无权图值为0或1
	InfoType info;//该弧相关信息
}ArcBox;
typedef struct
{
	VElemType vexs[MaxVex];//VElemType为顶点信息类型
	ArcBox arcs[MaxVex][MaxVex];//邻接矩阵,即边表
	int vexnum;//顶点数
	int arcnum;//边数
	int kind;//邻接矩阵的存储的图的种类:1有向图,2无向图,3有向网,4无向网
}MGraph;
class Graph
{
private:
	MGraph mg;
public:
	void CreateGraph();//创建图
	int LocateVex(VElemType x);//返回图中顶点x在顶点数组中的下标
	void CreateDG();//构造有向图
	void CreateUDG();//构造无向图
	void CreateDN();//构造有向网
	void CreateUDN();//构造无向网
	int DegreeGraph(VElemType x);//计算顶点的度数
	void ShortPath_DIJ(VElemType v);//求最短路径
	void Dispath(int dist[], int path[], int s[], VElemType x);//输出最短路径
	void Floyd();//Floyd算法求最短路径
	void Dispath(int dist[MaxVex][MaxVex]);//输出最短路径
};
✅2.4.1.2创建图
void Graph::CreateGraph()
{
	cout << "输入图的种类:1:有向图 2:无向图 3:有向网 4:无向网";
	cin >> mg.kind;
	switch (mg.kind)
	{
	case 1:CreateDG();//构造有向图
		break;
	case 2:CreateUDG();//构造无向图
		break;
	case 3:CreateDN();//构造有向网
		break;
	case 4:CreateUDN();//构造无向网
	}
}
✅2.4.1.3定位操作-查找顶点信息在顶点数组中的下标
int Graph::LocateVex(VElemType x)
{
	for (int i = 0; i < mg.vexnum; i++)
	{
		if (x == mg.vexs[i])
			return i;
	}
	return -1;
}
✅2.4.1.4创建有向图或无向图
void Graph::CreateDG()
{
	int i, j, h, t;
	VElemType u, v;
	int flag;//0表示没有弧信息,1表示有弧信息
	cin >> mg.vexnum >> mg.arcnum >> flag;
	for (int i = 0; i < mg.vexnum; i++)
	{
		cin >> mg.vexs[i];//构造顶点信息
	}
	for (i = 0; i < mg.vexnum; i++)
	{
		for (j = 0; j < mg.vexnum; j++)
		{
			mg.arcs[i][j].adj = 0;//用0初始化邻接矩阵
			mg.arcs[i][j].info = NULL;//用NULL初始化该弧的相关信息
		}
	}
	for (i = 0; i < mg.arcnum; i++)
	{
		cin >> u >> v;
		h = LocateVex(u);
		t = LocateVex(v);
		if (flag)
		{
			cin >> mg.arcs[h][t].info;
		}
		mg.arcs[h][t].adj = 1;//1表示顶点相邻
		mg.arcs[t][h].adj = 1;//若为无向图加上这条
	}
}
✅2.4.1.5创建有向网或无向网
void Graph::CreateDN()
{
	int i, j, h, t, w;
	VElemType u, v;
	int flag;//0表示没有弧信息,1表示有弧信息
	cin >> mg.vexnum >> mg.arcnum >> flag;
	for (int i = 0; i < mg.vexnum; i++)
	{
		cin >> mg.vexs[i];//构造顶点信息
	}
	for (i = 0; i < mg.vexnum; i++)
	{
		for (j = 0; j < mg.vexnum; j++)
		{
			if (i == j)
			{
				mg.arcs[i][j].adj = 0;//用0初始化邻接矩阵
			}
			else
			{
				mg.arcs[i][j].adj = MAXINT;
			}
			mg.arcs[i][j].info = NULL;//用NULL初始化该弧的相关信息
		}
	}
	for (i = 0; i < mg.arcnum; i++)
	{
		cin >> u >> v >> w;
		h = LocateVex(u);
		t = LocateVex(v);
		if (flag)
		{
			cin >> mg.arcs[h][t].info;
		}
		mg.arcs[h][t].adj = w;
		mg.arcs[t][h].adj = w;//若为无向网加上该赋值
	}
}
✅2.4.1.6计算顶点的度数-有向图为例
int Graph::DegreeGraph(VElemType x)
{
	int h = LocateVex(x);
	int count = 0;
	for (int i = 0; i < mg.vexnum; i++)
	{
		if (mg.arcs[h][i].adj && mg.arcs[h][i].adj != MAXINT)
			count++;
		if (mg.arcs[i][h].adj && mg.arcs[i][h].adj != MAXINT)
			count++;
	}
	return count;
}
✅2.4.1.7以有向图为例
#define _CRT_SECURE_NO_WARNINGS 1
#include 
using namespace std;
typedef int VElemType;
typedef int VRType;
typedef int InfoType;
#define MaxVex 20//预设最大顶点数
const int MAXINT = 0xfffffff;//最大 整数,表示无穷大
typedef struct 
{
	VRType adj;//VRType为顶点关系类型,对无权图值为0或1
	InfoType info;//该弧相关信息
}ArcBox;
typedef struct
{
	VElemType vexs[MaxVex];//VElemType为顶点信息类型
	ArcBox arcs[MaxVex][MaxVex];//邻接矩阵,即边表
	int vexnum;//顶点数
	int arcnum;//边数
	int kind;//邻接矩阵的存储的图的种类:1有向图,2无向图,3有向网,4无向网
}MGraph;
class Graph
{
private:
	MGraph mg;
public:
	void CreateGraph();//创建图
	int LocateVex(VElemType x);//返回图中顶点x在顶点数组中的下标
	void CreateDG();//构造有向图
	void CreateUDG();//构造无向图
	void CreateDN();//构造有向网
	void CreateUDN();//构造无向网
	int DegreeGraph(VElemType x);//计算有向图顶点的度数
};
void Graph::CreateGraph()
{
	cout << "输入图的种类:1:有向图 2:无向图 3:有向网 4:无向网"<<endl;
	cout << "请输入:";
	cin >> mg.kind;
	switch (mg.kind)
	{
	case 1:CreateDG();//构造有向图
		break;
	case 2:CreateUDG();//构造无向图
		break;
	case 3:CreateDN();//构造有向网
		break;
	case 4:CreateUDN();//构造无向网
	}
}
int Graph::LocateVex(VElemType x)
{
	for (int i = 0; i < mg.vexnum; i++)
	{
		if (x == mg.vexs[i])
			return i;
	}
	return -1;
}
void Graph::CreateDG()
{
	int i, j, h, t;
	VElemType u, v;
	int flag;//0表示没有弧信息,1表示有弧信息
	cout << "请输入顶点数、边数以及是否有弧信息(0/1)";
	cin >> mg.vexnum >> mg.arcnum >> flag;
	cout << "请输入" << mg.vexnum << "个顶点:";
	for (int i = 0; i < mg.vexnum; i++)
	{
		cin >> mg.vexs[i];//构造顶点信息
	}
	for (i = 0; i < mg.vexnum; i++)
	{
		for (j = 0; j < mg.vexnum; j++)
		{
			mg.arcs[i][j].adj = 0;//用0初始化邻接矩阵
			mg.arcs[i][j].info = NULL;//用NULL初始化该弧的相关信息
		}
	}
	for (i = 0; i < mg.arcnum; i++)
	{
		cout << "请输入关联的两个顶点:";
		cin >> u >> v;
		h = LocateVex(u);
		t = LocateVex(v);
		if (flag)
		{
			cout << "请输入权值:";
			cin >> mg.arcs[h][t].info;
		}
		mg.arcs[h][t].adj = 1;//1表示顶点相邻
	}
}
int Graph::DegreeGraph(VElemType x)
{
	int h = LocateVex(x);
	int count = 0;
	for (int i = 0; i < mg.vexnum; i++)
	{
		if (mg.arcs[h][i].adj && mg.arcs[h][i].adj != MAXINT)
			count++;
		if (mg.arcs[i][h].adj && mg.arcs[i][h].adj != MAXINT)
			count++;
	}
	cout << "该顶点的度数为:" << count << endl;
	return 0;
}
int main()
{
	Graph a;
	a.CreateGraph();
	a.DegreeGraph(1);
	a.DegreeGraph(2);
	a.DegreeGraph(3);
	a.DegreeGraph(4);
	return 0;
}

✅运行示例:
数据结构与算法-哈夫曼树与图_第12张图片

你可能感兴趣的:(初阶数据结构与算法,数据结构,c++,算法)