文档库 最新最全的文档下载
当前位置:文档库 › 数据结构(最小生成树普利姆算法)

数据结构(最小生成树普利姆算法)

数据结构(最小生成树普利姆算法)
数据结构(最小生成树普利姆算法)

一、问题分析和任务定义

在n个城市间建立通信网络,需架设n-1条线路。求解如何以最低经济代价建设此通信网,这是一个最小生成树问题。要求:(1)利用普利姆算法求网的最小生成树;(2)输出生成树中各边及权值。

二、实现本程序需要解决的问题如下

(1)、如何选择存储结构去建立一个带权网络。

(2)、如何在所选存储结构下输出这个带权网络。

(3)、如何实现PRIM算法的功能。

(4)、如何从每个顶点开始找到所有的最小生成树的顶点。

(5)、如何输出最小生成树的边及其权值。

此问题的关键在于如何实现PRIM算法,实现的过程中如何得到构成最小生成树的所有顶点,此外输出也是一个关键问题所在,在此过程中经过了多次调试。首先我们对问题进行大致的概要分析:

这个问题主要牵涉到通过PRIM的基本算法思想实现程序所要求的功能,该算法的主要思想是:假设N=(V,{E})是连通网,TE是N上最小生成树中边的集合。算法从U={u0}( u0∈V),TE={}开始,重复执行下述操作:在所有u∈U,v∈V-U的边(u,v)∈E中找一条代价最小的边(u0,v0)并入集合TE,同时v0并入U,直至U=V为止。此时TE中必有n-1条边,则T=(V,{E})为N的最小生成树。

问题的输入数据的格式为:首先提示输入带权网络的顶点边数,我定义的为整形数据型,然后输入每一条边的信息,即边的两个顶点以及权值,是十进制整数类型,这样我们就建立一个带权网络,并用邻接矩阵来存储,生成一个方阵显示出来。

问题的输出数据格式为:输出是以邻接矩阵存储结构下的方阵,以及从不同顶点开始省城的最小生成树。

题目要求以及达到目标:题目要求用普利姆算法实现任意给定的网和顶点的所有最小生成树,并且输出各边的权值。

三、测试数据

第一组

顶点数(vertices)、边数(edge):2、1

起始节点(starting)、下个节点(terminal)、权值(weights):1、2、5 ,预测结果<1,2>5

第二组

顶点数(vertices)、边数(edge):3、3

起始节点(starting)、下个节点(terminal)、权值(weights):1、2、4

1、3、5

2、3、6

预测结果<1,2>4、<1,3>5

第三组

顶点数(vertices)、边数(edge):4、5 ,

起始节点(starting)、下个节点(terminal)、权值(weights):1、2、3

1、3、4

1、4、6

2、4、7

3、4、5

预测结果<1,2>3、<1,3>4、<1,4>6

四、算法思想

Prim算法求最小生成树的主要思想

此算法是普利姆与1957年提出的一种构造最小生成树的算法,主要思想是:假设N=(V,{E})是连通网,TE是N上最小生成树中边的集合。算法从U={u0}( u0∈V),TE={}开始,重复执行下述操作:在所有u∈U,v∈V-U的边(u,v)∈E中找一条代价最小的边(u0,v0)并入集合TE,同时v0并入U,直至U=V为止。此时TE中必有n-1条边,则T=(V,{E})为N的最小生成树。

对于最小生成树问题

最小生成树是指在所有生成树中,边上权值之和最小的生成树,另外最小生成树也可能是多个,他们之间的权值之和相等。

五、模块划分

(1)预处理

#include

#include

#define inf 9999

#define max 40

#define linelenght 77

(2)普里姆算法

void prim(int g[][max],int n) /* prim的函数*/

{

int lowcost[max],closest[max];

int i,j,k,min;

for(i=2;i<=n;i++) /* n个顶点,n-1条边*/ { lowcost[i]=g[1][i]; /* 初始化*/

closest[i]=1; /* 顶点未加入到最小生成树中*/

}

lowcost[1]=0; /* 标志顶点1加入U集合*/ for(i=2;i<=n;i++) /* 形成n-1条边的生成树*/ {

min=inf;

k=0;

for(j=2;j<=n;j++) /* 寻找满足边的一个顶点在U,另一个顶点在V的最小边*/

if((lowcost[j]

{

min=lowcost[j];

k=j;

}

printf("(%d,%d)%d\t",closest[k],k,min);

lowcost[k]=0; /* 顶点k加入U */

for(j=2;j<=n;j++) /* 修改由顶点k到其他顶点边的权值*/

if(g[k][j]

{

lowcost[j]=g[k][j];

closest[j]=k;

}

printf("\n");

}

}

(3)输出分割线

int priline(int h) /* 输出一条分割线*/

{

int g;

printf("\n|");

for(g=0;g

printf("*");

printf("|\n");

}

(4)提示错误信息

int error() /* 提示错误信息*/

{

printf("\n\n|************************E*R*R*O*R************************|\ n");

printf("Input errors or Data overflow!!! please re-enter\n\n");

fflush(stdin); /* 清除缓存*/

}

(5)建立无向图

int adjg(int g[][max]) /* 建立无向图*/

{

int n,e,i,j,k,v1=0,v2=0,weight=0;

printf("Input the number of vertices, number of the edge:");

scanf("%d,%d",&n,&e);

while(e<=0||e>=n*(n-1)||n>=max)

{

error();

printf("Input the number of vertices, number of the edge:");

scanf("%d,%d",&n,&e);

}

for(i=1;i<=n;i++)

for(j=1;j<=n;j++)

g[i][j]=inf; /* 初始化矩阵,全部元素设为无穷大*/

for(k=1;k<=e;k++)

{

printf("Input the %d on the edge of the starting point, terminal, weights:",k);

scanf("%d,%d,%d",&v1,&v2,&weight);

while(v1==v2||v1>n||v2>n||v1<1||v2<1)

{

error();

printf("Input the %d on the edge of the starting point, terminal,

weights:",k);

scanf("%d,%d,%d",&v1,&v2,&weight);

}

g[v1][v2]=weight;

g[v2][v1]=weight;

}

return(n);

} /* 返回节点个数n */

(6)输出无向图的邻接矩阵

void pri(int g[][max],int n) /* 输出无向图的邻接矩阵*/ {

int i,j;

for(i=0;i<=n;i++)

printf("%d\t",i);

for(i=1;i<=n;i++)

{

printf("\n%d\t",i);

for(j=1;j<=n;j++) /* 输出边的权值*/

{

if(g[i][j]==inf) printf("%c\t",'\354');

else printf("%d\t",g[i][j]);

}

}

printf("\n");

}

(7)主函数模块

void main() /* 主函数*/

{

int g[max][max],n;priline(linelenght);

n=adjg(g);priline(linelenght);priline(linelenght);

printf("Input the adjacency matrix without directed graph:\n");

pri(g,n);

printf("\n");

printf("Minimum spanning tree structure:\n");

prim(g,n);

getch();

}

六、算法设计与分析

(1)关于带权网络的存储形式

要实现对于任意给定带权网络和顶点,运用PRIM基本算法思想求解所有的最小生成树的运算。在这里我们首先要明确所选用的数据结构,即选用何种数据结构存储来存储带权网络,这是必选首先解决的问题,所以我们选择了图的邻接矩阵存储方式来存储带权网络,建图时采用邻接矩阵的结构,定义邻接矩阵用到了一维数组和二维数组,分别存储顶点信息和边的权值。由于该算法对图中的边的权值频繁比较,所以采用邻接矩阵比较方便,并在此基础上实现带权网络的建立以及输出显示。

(2)关于普利姆算法的基本思想

Prim算法求最小生成树的主要思想

此算法是普利姆与1957年提出的一种构造最小生成树的算法,主要思想是:假设N=(V,{E})是连通网,TE是N上最小生成树中边的集合。算法从U={u0}( u0∈V),TE={}开始,重复执行下述操作:在所有u∈U,v∈V-U的边(u,v)∈E中找一条代价最小的边(u0,v0)并入集合TE,同时v0并入U,直至U=V为止。此时TE中必有n-1条边,则T=(V,{E})为N的最小生成树。

对于最小生成树问题

最小生成树是指在所有生成树中,边上权值之和最小的生成树,另外最小生成树也可能是多个,他们之间的权值之和相等。

(3)概要设计

通过邻接矩阵的建立,可以将任意两点的权值存入其中,便于进行各边的权值的比较修改,在普利姆算法中,为实现这个算法需附设一个辅助数组closedge,以记录从U到V-U具有最小代价的边,对每个顶点vi∈V-U,在辅助数组中存在一个相应分量closedge[i-1],他包括两个域,其中lowcost存储该边上的权值。显然,

closedge[i-1].lowcost=Min{cost(u,vi)| u∈U}

从算法可以看出每加入一个顶点到U中,closedge数组都会发生相应的变化。

程序模块之间的调用:在主函数中调用邻接矩阵的初始化函数,邻接矩阵的生成函数,PRIM算法的函数,图的构造函数,输出函数。邻接矩阵的生成函数主要解决的是边的信息存储问题,而PRIM算法的函数是解决计算出最小生成树的功能。

详细设计和编码

首先我在接下来给出总的流程:

结果分析:

本课程设计的要求

对于任意给定的网和起点,用PRIM算法的基本思想求解出所有的最小生成树并输出这些边的权值,所以如何实现输出显示所有的最小生成树关键问题所在,经过分析调试,用一个for语句就可以解决这个问题,从每个顶点出发,开始每一次遍历并输出显示出来。

算法的时间和空间性能分析

根据程序中算法的循环语句可以判断出普利姆算法的时间复杂度为O(n2)算法和图中的边数无关。因此普利姆算法适合求稠密网的最小生成树,因为在算法中用邻接矩阵的存储结构,在无向图中,邻接矩阵是对称的。所以仅需要存储上三角或下三角的元素,因此需要n(n+1)的存储空间。

测试结果

界面的截图

输入的情况的截图

输出结果的截图

输入错误的截图

七、源程序

源程序代码(有注释详解)

#include

#include

#define inf 9999

#define max 40

#define linelenght 77

void prim(int g[][max],int n) /* prim的函数*/

{

int lowcost[max],closest[max];

int i,j,k,min;

for(i=2;i<=n;i++) /* n个顶点,n-1条边*/ { lowcost[i]=g[1][i]; /* 初始化*/

closest[i]=1; /* 顶点未加入到最小生成树中*/

}

lowcost[1]=0; /* 标志顶点1加入U集合*/ for(i=2;i<=n;i++) /* 形成n-1条边的生成树*/ {

min=inf;

k=0;

for(j=2;j<=n;j++) /* 寻找满足边的一个顶点在U,另一个顶点在V的最小边*/

if((lowcost[j]

{

min=lowcost[j];

k=j;

}

printf("(%d,%d)%d\t",closest[k],k,min);

lowcost[k]=0; /* 顶点k加入U */

for(j=2;j<=n;j++) /* 修改由顶点k到其他顶点边的权值*/

if(g[k][j]

{

lowcost[j]=g[k][j];

closest[j]=k;

}

printf("\n");

}

}

int priline(int h) /* 输出一条分割线*/

{

int g;

printf("\n|");

for(g=0;g

printf("*");

printf("|\n");

}

int error() /* 提示错误信息*/

{

printf("\n\n|************************E*R*R*O*R************************|\ n");

printf("Input errors or Data overflow!!! please re-enter\n\n");

fflush(stdin); /* 清除缓存*/

}

int adjg(int g[][max]) /* 建立无向图*/

{

int n,e,i,j,k,v1=0,v2=0,weight=0;

printf("Input the number of vertices, number of the edge:");

scanf("%d,%d",&n,&e);

while(e<=0||e>=n*(n-1)||n>=max)

{

error();

printf("Input the number of vertices, number of the edge:");

scanf("%d,%d",&n,&e);

}

for(i=1;i<=n;i++)

for(j=1;j<=n;j++)

g[i][j]=inf; /* 初始化矩阵,全部元素设为无穷大*/

for(k=1;k<=e;k++)

{

printf("Input the %d on the edge of the starting point, terminal, weights:",k);

scanf("%d,%d,%d",&v1,&v2,&weight);

while(v1==v2||v1>n||v2>n||v1<1||v2<1)

{

error();

printf("Input the %d on the edge of the starting point, terminal, weights:",k);

scanf("%d,%d,%d",&v1,&v2,&weight);

}

g[v1][v2]=weight;

g[v2][v1]=weight;

}

return(n);

} /* 返回节点个数n */

void pri(int g[][max],int n) /* 输出无向图的邻接矩阵*/

{

int i,j;

for(i=0;i<=n;i++)

printf("%d\t",i);

for(i=1;i<=n;i++)

{

printf("\n%d\t",i);

for(j=1;j<=n;j++) /* 输出边的权值*/

{

if(g[i][j]==inf) printf("%c\t",'\354');

else printf("%d\t",g[i][j]);

}

}

printf("\n");

}

void main() /* 主函数*/

{

int g[max][max],n;priline(linelenght);

n=adjg(g);priline(linelenght);priline(linelenght);

printf("Input the adjacency matrix without directed graph:\n");

pri(g,n);

printf("\n");

printf("Minimum spanning tree structure:\n");

prim(g,n);

getch();

}

八、测试数据

第一组

第二组

第三组

九、课程设计项目进度表及任务分配表及任务分配表

十、设计心得

我们设计的题目是最小生成树的构造,在这次实践中遇到了各种问题,碰到问题有时总是百思不得其解

最开始,程序要求输入数值时,如果任意没有按照程序给定的类型输入,程序就会出现死循环,虽然加入了检测程序段,但是当我们不按个数输入的时候程序也出现了不稳定,又进入死循环了。我们想了很多办法,其中之一就是加入break这个函数。

不过,并没有出项我们想要的结果,导致循环检测输入的函数while无法继续执行,中途就中断了。有点大失所望,但是我们没有气馁。记得以前老是又用过清空缓存这个函数,会不会失这个原因呢?

int error() /* 提示错误信息 */

{

printf("\n\n|************************E*R*R*O*R*********************** *|\n");

printf("Input errors or Data overflow!!! please re-enter\n\n"); fflush(stdin); /* 清除缓存 */

}

经过我们反复测试,最终确定原因,正是出在这里,导致数据无法更新。

最小生成树主要由PRIM算法完成,由于老师平时课上对普利姆算法的知识的透彻讲解,通过整体构思,,于是,我们先确立了基本步骤:1.建立一个具有n个定点的无向图 2.接着创建一个邻接矩阵来存储该图,然后初始化该矩阵,最后根据普利姆算法,得到了最小生成树以及各边的权值;好的开头是成功的一半,按照这个步骤,我们忙碌了3天,在大家的共同努力下,我们总算将此程序设计出来。尽管不是自己独立完成,但仍然很欣慰,因为在设计的过程中,让我们了解到要设计一个大型程序,查找资料是至关重要的,在他人的基础上,再根据自己所学进行修改与调试,最后设计出自己想要的程序,这过程艰辛,但只要你持之以恒,定可将问题解决。通过本次实验巩固了课本的基本知识,熟练运用课程知识。提高我们组织数据及编写程序的能力,使我们能够根据问题要求和数据对象的特性,学会数据组织的方法,把现实世界中的问题在计算机内部表示出来并用软件解决问题,本次实验大大提高了对编程的爱好,发现,只要认认真真的去思考,没有办不到的事情,程序设计过程有

十、参考书目

参考目录书

(1)王昆仑,李红。数据结果算法:c语言版。中国铁道出版社,2007

(2)严蔚敏,吴伟明。数据结构:c语言版。清华大学出版社,2002

(3)徐孝凯,数据结构实用教程,清华大学出版社。2004

(4)耿国华,数据结构,c语言描述,西安电子科技大学出版社。2004

数据结构与算法--树的应用

实验报告 课程名称:数据结构与算法 实验名称:树的应用 一、实验目的 ⑴、掌握二叉树的静态数组存放。 ⑵、掌握哈夫曼编码的基本概念。 ⑶、掌握哈夫曼编码树的构造方法。 ⑷、掌握哈夫曼编码的构造和使用。 ⑸、理解前缀编码的概念。 二、实验内容 ⑴、按照字符出现概率构造一个哈夫曼树。要求输入为一个文本文件(可以限 制文本仅仅包含字母),通过统计字符出现的次数计算概率,在此基础上构造哈夫曼树。 ⑵、打印出每一个字母对应的哈夫曼编码。 三、实验环境 硬件:Windows XP计算机、鼠标、键盘、显示器 开发环境:Microsoft Visual C++ 6.0 四、实验步骤 ①、点击开始菜单中的程序-Microsoft Visual C++ 6.0 点击菜单栏中的文件—新建—文件—C++ Source File ,在文件名(N)中写入5.cpp,再点击确定. ②、编写程序如下: #include #define MAXV ALUE 10000//定义最大权值 #define MAXLEAF 100//定义哈夫曼树中最大叶子节点个数 #define MAXNODE MAXLEAF*2-1//哈夫曼树的最大节点数 #define MAXBIT 30//定义哈夫曼编码的最大长度 #define MAX 100 typedef struct { int weight; int parent,lchild,rchild; }HufNodeType; typedef struct { int bit[MAXBIT]; int start;//编码的起位 }HufCodeType;//哈夫曼编码的结构体 void HuffmanTree(HufNodeType HuffNode[],int *w,int n)//建立哈夫曼树

数据结构与算法基础知识总结

数据结构与算法基础知识总结 1 算法 算法:是指解题方案的准确而完整的描述。 算法不等于程序,也不等计算机方法,程序的编制不可能优于算法的设计。 算法的基本特征:是一组严谨地定义运算顺序的规则,每一个规则都是有效的,是明确的,此顺序将在有限的次数下终止。特征包括: (1)可行性; (2)确定性,算法中每一步骤都必须有明确定义,不充许有模棱两可的解释,不允许有多义性; (3)有穷性,算法必须能在有限的时间内做完,即能在执行有限个步骤后终止,包括合理的执行时间的含义; (4)拥有足够的情报。 算法的基本要素:一是对数据对象的运算和操作;二是算法的控制结构。 指令系统:一个计算机系统能执行的所有指令的集合。 基本运算和操作包括:算术运算、逻辑运算、关系运算、数据传输。 算法的控制结构:顺序结构、选择结构、循环结构。 算法基本设计方法:列举法、归纳法、递推、递归、减斗递推技术、回溯法。 算法复杂度:算法时间复杂度和算法空间复杂度。 算法时间复杂度是指执行算法所需要的计算工作量。 算法空间复杂度是指执行这个算法所需要的内存空间。 2 数据结构的基本基本概念 数据结构研究的三个方面: (1)数据集合中各数据元素之间所固有的逻辑关系,即数据的逻辑结构; (2)在对数据进行处理时,各数据元素在计算机中的存储关系,即数据的存储结构;(3)对各种数据结构进行的运算。 数据结构是指相互有关联的数据元素的集合。 数据的逻辑结构包含: (1)表示数据元素的信息; (2)表示各数据元素之间的前后件关系。 数据的存储结构有顺序、链接、索引等。 线性结构条件:

(1)有且只有一个根结点; (2)每一个结点最多有一个前件,也最多有一个后件。 非线性结构:不满足线性结构条件的数据结构。 3 线性表及其顺序存储结构 线性表由一组数据元素构成,数据元素的位置只取决于自己的序号,元素之间的相对位置是线性的。 在复杂线性表中,由若干项数据元素组成的数据元素称为记录,而由多个记录构成的线性表又称为文件。 非空线性表的结构特征: (1)且只有一个根结点a1,它无前件; (2)有且只有一个终端结点an,它无后件; (3)除根结点与终端结点外,其他所有结点有且只有一个前件,也有且只有一个后件。结点个数n称为线性表的长度,当n=0时,称为空表。 线性表的顺序存储结构具有以下两个基本特点: (1)线性表中所有元素的所占的存储空间是连续的; (2)线性表中各数据元素在存储空间中是按逻辑顺序依次存放的。 ai的存储地址为:adr(ai)=adr(a1)+(i-1)k,,adr(a1)为第一个元素的地址,k代表每个元素占的字节数。 顺序表的运算:插入、删除。(详见14--16页) 4 栈和队列 栈是限定在一端进行插入与删除的线性表,允许插入与删除的一端称为栈顶,不允许插入与删除的另一端称为栈底。 栈按照“先进后出”(filo)或“后进先出”(lifo)组织数据,栈具有记忆作用。用top表示栈顶位置,用bottom表示栈底。 栈的基本运算:(1)插入元素称为入栈运算;(2)删除元素称为退栈运算;(3)读栈顶元素是将栈顶元素赋给一个指定的变量,此时指针无变化。 队列是指允许在一端(队尾)进入插入,而在另一端(队头)进行删除的线性表。rear指针指向队尾,front指针指向队头。 队列是“先进行出”(fifo)或“后进后出”(lilo)的线性表。 队列运算包括(1)入队运算:从队尾插入一个元素;(2)退队运算:从队头删除一个元素。循环队列:s=0表示队列空,s=1且front=rear表示队列满

《数据结构与算法》课后习题答案

2.3 课后习题解答 2.3.2 判断题 1.线性表的逻辑顺序与存储顺序总是一致的。(×) 2.顺序存储的线性表可以按序号随机存取。(√) 3.顺序表的插入和删除操作不需要付出很大的时间代价,因为每次操作平均只有近一半的元素需要移动。(×) 4.线性表中的元素可以是各种各样的,但同一线性表中的数据元素具有相同的特性,因此属于同一数据对象。(√) 5.在线性表的顺序存储结构中,逻辑上相邻的两个元素在物理位置上并不一定相邻。(×) 6.在线性表的链式存储结构中,逻辑上相邻的元素在物理位置上不一定相邻。(√)7.线性表的链式存储结构优于顺序存储结构。(×) 8.在线性表的顺序存储结构中,插入和删除时移动元素的个数与该元素的位置有关。(√) 9.线性表的链式存储结构是用一组任意的存储单元来存储线性表中数据元素的。(√)10.在单链表中,要取得某个元素,只要知道该元素的指针即可,因此,单链表是随机存取的存储结构。(×) 11.静态链表既有顺序存储的优点,又有动态链表的优点。所以它存取表中第i个元素的时间与i无关。(×) 12.线性表的特点是每个元素都有一个前驱和一个后继。(×) 2.3.3 算法设计题 1.设线性表存放在向量A[arrsize]的前elenum个分量中,且递增有序。试写一算法,将x 插入到线性表的适当位置上,以保持线性表的有序性,并且分析算法的时间复杂度。【提示】直接用题目中所给定的数据结构(顺序存储的思想是用物理上的相邻表示逻辑上的相邻,不一定将向量和表示线性表长度的变量封装成一个结构体),因为是顺序存储,分配的存储空间是固定大小的,所以首先确定是否还有存储空间,若有,则根据原线性表中元素的有序性,来确定插入元素的插入位置,后面的元素为它让出位置,(也可以从高下标端开始一边比较,一边移位)然后插入x ,最后修改表示表长的变量。 int insert (datatype A[],int *elenum,datatype x) /*设elenum为表的最大下标*/ {if (*elenum==arrsize-1) return 0; /*表已满,无法插入*/ else {i=*elenum; while (i>=0 && A[i]>x) /*边找位置边移动*/ {A[i+1]=A[i]; i--; } A[i+1]=x; /*找到的位置是插入位的下一位*/ (*elenum)++; return 1; /*插入成功*/ } } 时间复杂度为O(n)。

数据结构与算法-北大 HW11 B_B+树

北京大学信息学院2007年秋季学期《数据结构与算法A(实验班)》课程作业 张铭编写并发布 mzhang@https://www.wendangku.net/doc/e614666544.html, 第11次作业,12月17日(周一)课前提交,电子稿提交时间12月17日开课之前提交。 11.1 偶数阶的B 树插入上溢出时,中 位数有两个,需要注意采用统一的策略。例如,取第二个中位数, 即分裂后左(1)/2m ?????个关键码,右(1)/2m ?????; 或者取第一个中位数,分裂后左(1)/2m ????? 右(1)/2m ?????。请画出对右图的4阶B 树进行下来操作后的B 树。 (1) 分裂时采用第2个中位数为 分界码,请画出插入关键码113后的B 树;分析插入操作的访外次数。 (2) 分裂时采用第1个中位数为分界码,请画出插入关键码113后的B 树;分析插入操 作的访外次数。 (3) 在原树中删除关键码50;分析删除操作的访外次数(与1、2题无关,从根重新开 始操作)。 11.2 已知一组关键码为(20, 30, 50, 52, 60, 68, 70),试依次插入关键码。 (1) 生成一棵3阶的B +树,画出插入所有关键码后B 树的结构。 (2) 画出删除50后的B + 状态,分析删除操作的访外次数。 11.3 假设一个数据文件每个记录对象需要占用128 字节(其中关键码占用4字节),且所 有记录均已按关键码有序地存储在主磁盘文件中。设磁盘页块大小为2048(= 2K )字节,若主存中有12M 空间可以用来存储索引结构,索引项中每一个地址指针占8 字节。请简要回答以下问题(请写明你的计算过程)。 (1) 使用B 树索引,B 树的阶m 1最多可以为多少?4层m 1阶B 树,最多可以索引多 少字节的数据文件? (2) 使用B +树索引,B +树的阶m 2最多可以为多少? (3) 假设B +树的叶层各结点链接成双链结构,B +树的叶结点阶m 2’可以跟内部结点不 一样,则阶m 2’为多少? (4) 在第(3)小题的基础上,计算4层B +树(内部结点为m 2阶,叶结点m 2’阶),最多 可以索引多少字节的数据文件? (5) 假设尽量把B +树的头几层放入内存(本题规定不能超过12M ),那么给定关键码, 通过B +树查找到(4)小题中主数据文件的一个记录,最少几次访外?最多几次访 外? 11.4 对于下面两种B +树,列表给出他们在1、2、3、4和5层(独根是一层树)的不同情 况下,能够存储的最大记录数和最小记录数。 (1) 对于教材定义那样的B +树,其内部结点阶为50,叶结点阶为50。 (2) 如讲义P89那样的混合型B +树,其内部结点阶为55,叶结点阶为25(叶结点除关 键码,还索引部分记录信息)。 4阶B 树

武汉理工大学数据结构与算法综合实验哈夫曼树(1)

学生学号Xxx实验课成绩 学生实验报告书 实验课程名称数据结构与算法综合实验 开课学院计算机科学与技术学院 指导教师姓名xxx 学生姓名xxx 学生专业班级xxxx 2015--2016学年第2学期

实验课程名称:数据结构与算法综合实验 实验项目名称二叉树与赫夫曼图片压缩报告成绩 实验者xx专业班级xxx组别 同组者完成日期2016年5月 2日第一部分:实验分析与设计(可加页) 一、实验目的和要求 1.目的 掌握树的存储结构 掌握二叉树的三种遍历方法 掌握 Huffman树、Huffman编码等知识和应用 使用 C++、文件操作和 Huffman算法实现“图片压缩程序”专题编程。 2.要求 针对一幅 BMP 格式的图片文件,统计 256 种不同字节的重复次数,以每种字 节重复次数作为权值,构造一颗有 256 个叶子节点的哈夫曼二叉树。 利用上述哈夫曼树产生的哈夫曼编码对图片文件进行压缩。 压缩后的文件与原图片文件同名,加上后缀.huf (保留原后缀),如 pic.bmp 压 缩后 pic.bmp.huf 二、分析与设计 依据上述的实验目的与要求,可导出实现的二叉树与赫夫曼图片压缩软件的流程为: ① 读取图片文件、统计权值 ②生成 Huffman树 ③生成 Huffman编码 ④ 压缩图片文件 ⑤ 保存压缩的文件 1.数据结构的设计 记录统计 256种不同字节的重复次数使用整型数组。 int weight[256] = { 0 }; 二叉树的存储结构。使用结构体存储节点,使用数组存储树的节点,使用静态二叉链表方 式存储二叉树。 Huffman编码存储结构 struct HTNode { int weight;//权值

数据结构树的有关算法

《数据结构》课程设计任务书 学期:11-12-2 班级:网络10 一、设计目的 《数据结构》是一门实践性较强的专业基础课程,为了学好这门课程,必须在掌握理论知识的同时,加强上机实践。本课程设计的目的就是要达到理论与实际应用相结合,使同学们能够根据数据对象的特性,学会数据组织的方法,能把现实世界中的实际问题在计算机内部表示出来,并培养基本的、良好的程序设计技能。 二、设计要求 1、通过这次设计,要求在数据结构的逻辑特性和物理表示、数据结构的选择应用、算法的设计及其实现等方面加深对课程基本内容的理解。同时,在程序设计方法以及上机操作等基本技能和科学作风方面受到比较系统和严格的训练。 2、学生必须仔细研读《数据结构》课程设计(实习)要求,以学生自学为主、指导教师指导为辅,认真、独立地完成课程设计的任务,有问题及时主动与指导教师沟通。 3、本次课程设计按照教学要求需要在一周半时间内独立完成,学生要发挥自主学习的能力,充分利用时间,安排好课设的时间计划,并在课设过程中不断检测自己的计划完成情况,及时地向指导教师汇报。 4、编程语言任选。 三、设计选题 题一:线索二叉树(**) 任务: 1.建立中序线索二叉树,并且中序遍历; 2.求中序线索二叉树上已知结点中序的前驱和后继; 需求分析和概要设计: 建立中序线索二叉树,并且中序遍历。首先就是要建立树,再将树中序线索化。求中序线索二叉树上已知结点中序的前驱和后继时,即是将树在遍历一遍。也可以在遍历的过程中,将树的结点放在数组中,当然必须讲述先遍历一遍,这是用空间来换时间。 详细设计: 树的结构体的声明: typedef char TElemtype; typedef enum PointerTag{Link,Thread}; //设置标志:Link为指针,Thread为线索typedef struct BiThrNode{ //树结点结构体 TElemtype data; struct BiThrNode *lchild,*rchild; PointerTag LTag,RTag; }BiThrNode,*BiThrTree; 相关函数的声明:

贪心算法实验(最小生成树)

算法分析与设计实验报告第一次附加实验

附录: 完整代码(贪心法) //贪心算法最小生成树prim算法 #include #include #include #include #include using namespace std; #define inf 9999; //定义无限大的值const int N=6; template //模板定义 void Prim(int n,Type c[][N+1]); int main() { int c[N+1][N+1]; cout<<"连通带权图的矩阵为:"<

cin>>c[i][j]; } } cout<<"Prim算法最小生成树选边次序如下:"< //参数为结点个数n,和无向带权图中各结点之间的距离c[][N+1] void Prim(int n,Type c[][N+1]) { Type lowcost[N+1]; //记录c[j][closest]的最小权值 int closest[N+1]; //V-S中点j在s中的最临接顶点 bool s[N+1]; //标记各结点是否已经放入S集合| s[1]=true; //初始化s[i],lowcost[i],closest[i] for(int i=2;i<=n;i++) { lowcost[i]=c[1][i]; closest[i]=1; s[i]=false; } for(int i=1;i

数据结构与算法C语言版期末复习题

《数据结构与算法》期末复习题 一、选择题。 1.在数据结构中,从逻辑上可以把数据结构分为 C 。 A.动态结构和静态结构B.紧凑结构和非紧凑结构 C.线性结构和非线性结构D.内部结构和外部结构 2.数据结构在计算机内存中的表示是指 A 。 A.数据的存储结构B.数据结构C.数据的逻辑结构D.数据元素之间的关系 3.在数据结构中,与所使用的计算机无关的是数据的 A 结构。 A.逻辑B.存储C.逻辑和存储D.物理 4.在存储数据时,通常不仅要存储各数据元素的值,而且还要存储 C 。 A.数据的处理方法B.数据元素的类型 C.数据元素之间的关系D.数据的存储方法 5.在决定选取何种存储结构时,一般不考虑 A 。 A.各结点的值如何B.结点个数的多少 C.对数据有哪些运算D.所用的编程语言实现这种结构是否方便。 6.以下说法正确的是 D 。 A.数据项是数据的基本单位 B.数据元素是数据的最小单位 C.数据结构是带结构的数据项的集合 D.一些表面上很不相同的数据可以有相同的逻辑结构 7.算法分析的目的是 C ,算法分析的两个主要方面是 A 。 (1)A.找出数据结构的合理性B.研究算法中的输入和输出的关系C.分析算法的效率以求改进C.分析算法的易读性和文档性 (2)A.空间复杂度和时间复杂度B.正确性和简明性 C.可读性和文档性D.数据复杂性和程序复杂性 8.下面程序段的时间复杂度是O(n2) 。 s =0; for( I =0; i

算法与数据结构实验报告——树及其应用

北京邮电大学软件学院 2019-2020学年第1学期实验报告 课程名称:算法与数据结构课程设计 实验名称:树及其应用 实验完成人: 日期: 2019 年 11月 10 日

一、实验目的 树是一种应用极为广泛的数据结构,也是这门课程的重点。它们的特点在于非线性。 广义表本质上是树结构。本章实验继续突出了数据结构加操作的程序设计观点,但根据这两种结构的非线性特点,将操作进一步集中在遍历操作上,因为遍历操作是其他众多操作的基础。遍历逻辑的(或符号形式的)结构,访问动作可是任何操作。 本次实验希望帮助学生熟悉各种存储结构的特征,以及如何应用树结构解决具体问题(即原理与应用的结合)。 二、实验内容 必做内容 1)二叉树的建立与遍历 [问题描述] 建立一棵二叉树,并对其进行遍历(先序、中序、后序),打印输出遍历结果。 [基本要求] 从键盘接受输入(先序),以二叉链表作为存储结构,建立二叉树(以先序来建立),并采用递归算法对其进行遍历(先序、中序、后序),将遍历结果打印输出。 [测试数据] ABCффDEфGффFффф(其中ф表示空格字符)则输出结果为 先序:ABCDEGF 中序:CBEGDFA 后序:CGBFDBA 2)打印二叉树结构 [问题描述] 按凹入表形式横向打印二叉树结构,即二叉树的根在屏幕的最左边,二叉树的左子树在屏幕的下边,二叉树的右子树在屏幕的上边。例如: [测试数据] 由学生依据软件工程的测试技术自己确定。注意测试边界数据,如空二叉树。

[实现提示] (1)利用RDL遍历方法; (2)利用结点的深度控制横向位置。 选做内容 采用非递归算法实现二叉树遍历。 三、实验环境 Windows下利用vs 2019完成,语言c++ 四、实验过程描述 首先构造Tree类,内含树的结构体BiTree,以及本实验所要用到的一些操作 typedef struct BiTNode { TElemType data; int degree, depth, level; //度,高度,高度差 struct BiTNode* lchild, * rchild; /* 左右孩子指针 */ }BiTNode, * BiTree; 实现相应功能: 1、二叉树的建立与遍历 构造二叉树: 前序构造,先赋值,然后递归构造左子树,递归构造右函数 BiTNode* Tree::CreatBiTree(BiTree T) { TElemType ch; cin >> noskipws >> ch; //不跳过空格 if (ch == ' ') T = NULL; //输入空格表示空子树 else { T = new BiTNode; //分配空间 if(!T) //分配失败就退出 throw new std::bad_alloc; T->degree = 0; //记录度 (T)->data = ch; T->depth++; //度增加 T->lchild=CreatBiTree(T->lchild); //递归创建左子树 T->rchild=CreatBiTree(T->rchild); //递归创建右子树 if (T->lchild != NULL) T->degree++; //有一个孩子度就加一

二叉排序树运算-数据结构与算法课程设计报告_l

合肥学院 计算机科学与技术系 课程设计报告 2009 ~2010 学年第二学期 课程 数据结构与算法 课程设计 名称 二叉排序树运算学生姓名顾成方 学号0704011033 专业班级08计科(2) 指导教师王昆仑张贯虹 2010 年 5 月

题目:(二叉排序树运算问题)设计程序完成如下要求:对一组数据构造二叉排序树,并在二叉排序树中实现多种方式的查找。基本任务:⑴选择合适的储存结构构造二叉排序树;⑵对二叉排序树T作中序遍历,输出结果;⑶在二叉排序树中实现多种方式的查找,并给出二叉排序树中插入和删除的操作。 ⑷尽量给出“顺序和链式”两种不同结构下的操作,并比较。 一、问题分析和任务定义 本次程序需要完成如下要求:首先输入任一组数据,使之构造成二叉排序树,并对其作中序遍历,然后输出遍历后的数据序列;其次,该二叉排序树能实现对数据(即二叉排序树的结点)的查找、插入和删除等基本操作。 实现本程序需要解决以下几个问题: 1、如何构造二叉排序树。 2、如何通过中序遍历输出二叉排序树。 3、如何实现多种查找。 4、如何实现插入删除等操作。 二叉排序树的定义:

⑴其左子树非空,则左子树上所有结点的值均小于根结点的值。 ⑵若其右子树非空,则右子树上所有结点的值大于根结点的值。 ⑶其左右子树也分别为二叉排序树。 本问题的关键在于对于二叉排序树的构造。根据上述二叉排序树二叉排序树的生成需要通过插入算法来实现:输入(插入)的第一个数据即为根结点;继续插入,当插入的新结点的关键值小于根结点的值时就作为左孩子,当插入的新结点的关键值大于根结点的值时就作为右孩子;在左右子树中插入方法与整个二叉排序树相同。当二叉排序树建立完成后,要插入新的数据时,要先判断已建立的二叉排序树序列中是否已有当前插入数据。因此,插入算法还要包括对数据的查找判断过程。 本问题的难点在于二叉排序树的删除算法的实现。删除前,首先要进行查找,判断给出的结点是否已存在于二叉排序树之中;在删除时,为了保证删除结点后的二叉树仍为二叉排序树,要考虑各种情况,选择正确

最小生成树问题的算法实现及复杂度分析—天津大学计算机科学与技术学院(算法设计与分析)

算法设计与分析课程设计报告 学院计算机科学与技术 专业计算机科学与技术 年级2011 姓名XXX 学号 2013年5 月19 日

题目:最小生成树问题的算法实现及复杂度分析 摘要:该程序操作简单,具有一定的应用性。数据结构是计算机科学的算法理论基础和软件设计的技术基础,在计算机领域中有着举足轻重的作用,是计算机学科的核心课程。而最小生成树算法是算法设计与分析中的重要算法,最小生成树也是最短路径算法。最短路径的问题在现实生活中应用非常广泛,如邮递员送信、公路造价等问题。本设计以Visual Studio 2010作为开发平台,C/C++语言作为编程语言,以邻接矩阵作为存储结构,编程实现了最小生成树算法。构造最小生成树有很多算法,本文主要介绍了图的概念、图的遍历,并分析了PRIM 经典算法的算法思想,最后用这种经典算法实现了最小生成树的生成。 引言:假设要在n个城市之间建立通信联络网,则连接n个城市只需要n-1条线路。这时,自然会考虑这样一个问题,如何在节省费用的前提下建立这个通信网?自然在每两个城市之间都可以设置一条线路,而这相应的就要付出较高的经济代价。n个城市之间最多可以设置n(n-1)/2条线路,那么如何在这些可能的线路中选择n-1 条使总的代价最小呢?可以用连通网来表示n 个城市以及n个城市之间可能设置的通信线路,其中网的顶点表示城市,边表示两个城市之间的线路,赋予边的权值表示相应的代价。对于n个顶点的连通网可以建立许多不同的生成树,每一个生成树都可以是一个通信网。现在要选择这样一棵生成树,也就是使总的代价最小。这个问题便是构造连通网的最小代价生成树(简称最小生成树)的问题。最小生成树是指在所有生成树中,边上权值之和最小的生成树,另外最小生成树也可能是多个,他们之间的权值之和相等。一棵生成树的代价就是树上各边的代价之和。而实现这个运算的经典算法就是普利姆算法。

数据结构与算法试题

数据结构与算法试题 一、单选题 1、在数据结构的讨论中把数据结构从逻辑上分为 (C ) A 内部结构与外部结构 B 静态结构与动态结构 C 线性结构与非线性结构 D 紧凑结构与非紧凑结构。 2、采用线性链表表示一个向量时,要求占用的存储空间地址(D ) A 必须就是连续的 B 部分地址必须就是连续的 C 一定就是不连续的 D 可连续可不连续 3、采用顺序搜索方法查找长度为n的顺序表时,搜索成功的平均搜索长度为( D )。 A n B n/2 C (n-1)/2 D (n+1)/2 4、在一个单链表中,若q结点就是p结点的前驱结点,若在q与p之间插入结点s,则执行( D )。 A s→link = p→link;p→link = s; B p→link = s; s→link = q; C p→link = s→link;s→link = p; D q→link = s;s→link = p; 5、如果想在4092个数据中只需要选择其中最小的5个,采用( C )方法最好。 A 起泡排序 B 堆排序 C 锦标赛排序 D 快速排序 6、设有两个串t与p,求p在t中首次出现的位置的运算叫做( B )。 A 求子串 B 模式匹配 C 串替换 D 串连接 7、在数组A中,每一个数组元素A[i][j]占用3个存储字,行下标i从1到8,列下标j从1到10。所有数组元素相继存放于一个连续的存储空间中,则存放该数

组至少需要的存储字数就是( C )。 A 80 B 100 C 240 D 270 8、将一个递归算法改为对应的非递归算法时,通常需要使用( A )。 A 栈 B 队列 C 循环队列 D 优先队列 9、一个队列的进队列顺序就是1, 2, 3, 4,则出队列顺序为( C )。 10、在循环队列中用数组A[0、、m-1] 存放队列元素,其队头与队尾指针分别为front与rear,则当前队列中的元素个数就是( D )。 A ( front - rear + 1) % m B ( rear - front + 1) % m C ( front - rear + m) % m D ( rear - front + m) % m 11、一个数组元素a[i]与( A )的表示等价。 A *(a+i) B a+i C *a+i D &a+i 12、若需要利用形参直接访问实参,则应把形参变量说明为( B )参数。 A 指针 B 引用 C 值 D 变量 13、下面程序段的时间复杂度为( C ) for (int i=0;i

kruskal算法求最小生成树

#include #include #include #include using namespace std; #define maxn 110 //最多点个数 int n, m; //点个数,边数 int parent[maxn]; //父亲节点,当值为-1时表示根节点 int ans; //存放最小生成树权值 struct eage //边的结构体,u、v为两端点,w为边权值

{ int u, v, w; }EG[5010]; bool cmp(eage a, eage b) //排序调用 { return a.w < b.w; } int Find(int x) //寻找根节点,判断是否在同一棵树中的依据 { if(parent[x] == -1) return x; return Find(parent[x]); } void Kruskal() //Kruskal算法,parent能够还原一棵生成树,或者森林{ memset(parent, -1, sizeof(parent)); sort(EG+1, EG+m+1, cmp); //按权值将边从小到大排序 ans = 0; for(int i = 1; i <= m; i++) //按权值从小到大选择边 { int t1 = Find(EG[i].u), t2 = Find(EG[i].v); if(t1 != t2) //若不在同一棵树种则选择该边,合并两棵树 { ans += EG[i].w; parent[t1] = t2; printf("最小生成树加入的边为:%d %d\n",EG[i].u,EG[i].v); } } } int main() { printf("输入顶点数和边数:"); while(~scanf("%d%d", &n,&m)) { for(int i = 1; i <= m; i++) scanf("%d%d%d", &EG[i].u, &EG[i].v, &EG[i].w); Kruskal(); printf("最小生成树权值之和为:%d\n", ans); } return 0; }

数据结构与算法第三版第章参考答案

习题参考答案 一.选择题 1.从逻辑上可以把数据结构分为(C)两大类。 A.动态结构、静态结构 B.顺序结构、链式结构 C.线性结构、非线性结构 D.初等结构、构造型结构 2.在下面的程序段中,对x的斌值语句的频度为(C)。 for( t=1;k<=n;k++) for(j=1;j<=n; j++) x=x十1; A. O(2n) B. O (n) C. O (n2). D. O(1og2n) 3.采用顺序存储结构表示数据时,相邻的数据元素的存储地址(A)。 A.一定连续B.一定不连续 C.不一定连续 D.部分连续,部分不连续 4.下面关于算法说法正确的是(D)。 A.算法的时间复杂度一般与算法的空间复杂度成正比 B.解决某问题的算法可能有多种,但肯定采用相同的数据结构 C.算法的可行性是指算法的指令不能有二义性 D.同一个算法,实现语言的级别越高,执行效率就越低 5.在发生非法操作时,算法能够作出适当处理的特性称为(B)。 A.正确性 B.健壮性 C.可读性 D.可移植性 二、判断题 1.数据的逻辑结构是指数据的各数据项之间的逻辑关系。(√) 2.顺序存储方式的优点是存储密度大,且插人、删除运算效率高。(×) 3.数据的逻辑结构说明数据元素之间的次序关系,它依赖于数据的存储结构。(×) 4.算法的优劣与描述算法的语言无关,但与所用计算机的性能有关。(×) 5.算法必须有输出,但可以没有输人。(√) 三、筒答题 1.常见的逻辑结构有哪几种,各自的特点是什么?常用的存储结构有哪几种,各自的特点是什么? 【答】常见的四种逻辑结构: ①集合结构:数据元素之间是“属于同一个集合” ②线性结构:数据元素之间存在着一对一的关系 ③树结构:数据元素之间存在着一对多的关系 ④结构:数据元素之间存在着多对多的关系。 常见的四种存储结构有: ①顺序存储:把逻辑上相邻的元素存储在物理位置相邻的存储单元中。顺序存储结构是一种最基本的存储表示方法,通常借助于程序设计语言中的数组来实现。 ②链接存储:对逻辑上相邻的元素不要求物理位置相邻的存储单元,元素间的逻辑关系通过附设的指针域来表示。 ③索引存储:通过建立索引表存储结点信息的方法,其中索引表一般存储结点关键字和一个地点信息,可通过该地址找到结点的其他信息。 ④散列存储:根据结点的关键字直接计算出该结点的存储地址的方法。 2.简述算法和程序的区别。 【解答】一个算法若用程序设计语言来描述,则它就是一个程序。算法的含义与程序十分相

第六章树和二叉树习题数据结构

习题六树和二叉树 一、单项选择题 1.以下说法错误的是 ( ) A.树形结构的特点是一个结点可以有多个直接前趋 B.线性结构中的一个结点至多只有一个直接后继 C.树形结构可以表达(组织)更复杂的数据 D.树(及一切树形结构)是一种"分支层次"结构 E.任何只含一个结点的集合是一棵树 2.下列说法中正确的是 ( ) A.任何一棵二叉树中至少有一个结点的度为2 B.任何一棵二叉树中每个结点的度都为2 C.任何一棵二叉树中的度肯定等于2 D.任何一棵二叉树中的度可以小于2 3.讨论树、森林和二叉树的关系,目的是为了() A.借助二叉树上的运算方法去实现对树的一些运算 B.将树、森林按二叉树的存储方式进行存储 C.将树、森林转换成二叉树 D.体现一种技巧,没有什么实际意义 4.树最适合用来表示 ( ) A.有序数据元素 B.无序数据元素 C.元素之间具有分支层次关系的数据 D.元素之间无联系的数据 5.若一棵二叉树具有10个度为2的结点,5个度为1的结点,则度为0的结点个数是()A.9 B.11 C.15 D.不确定 6.设森林F中有三棵树,第一,第二,第三棵树的结点个数分别为M1,M2和M3。与森林F对应的二叉树根结点的右子树上的结点个数是()。 A.M1 B.M1+M2 C.M3 D.M2+M3 7.一棵完全二叉树上有1001个结点,其中叶子结点的个数是() A. 250 B. 500 C.254 D.505 E.以上答案都不对 8. 设给定权值总数有n 个,其哈夫曼树的结点总数为( ) A.不确定 B.2n C.2n+1 D.2n-1 9.二叉树的第I层上最多含有结点数为() A.2I B. 2I-1-1 C. 2I-1 D.2I -1 10.一棵二叉树高度为h,所有结点的度或为0,或为2,则这棵二叉树最少有( )结点A.2h B.2h-1 C.2h+1 D.h+1 11. 利用二叉链表存储树,则根结点的右指针是()。 A.指向最左孩子 B.指向最右孩子 C.空 D.非空 14.在二叉树结点的先序序列,中序序列和后序序列中,所有叶子结点的先后顺序()A.都不相同 B.完全相同 C.先序和中序相同,而与后序不同 D.中序和后序相同,而与先序不同 15.在完全二叉树中,若一个结点是叶结点,则它没()。 A.左子结点 B.右子结点 C.左子结点和右子结点 D.左子结点,右子结点和兄弟结点 16.在下列情况中,可称为二叉树的是()

最小生成树算法分析

最小生成树算法分析 一、生成树的概念 若图是连通的无向图或强连通的有向图,则从其中任一个顶点出发调用一次bfs或dfs后便可以系统地访问图中所有顶点;若图是有根的有向图,则从根出发通过调用一次dfs或bfs亦可系统地访问所有顶点。在这种情况下,图中所有顶点加上遍历过程中经过的边所构成的子图称为原图的生成树。 对于不连通的无向图和不是强连通的有向图,若有根或者从根外的任意顶点出发,调用一次bfs或dfs后一般不能系统地访问所有顶点,而只能得到以出发点为根的连通分支(或强连通分支)的生成树。要访问其它顶点需要从没有访问过的顶点中找一个顶点作为起始点,再次调用bfs 或dfs,这样得到的是生成森林。 由此可以看出,一个图的生成树是不唯一的,不同的搜索方法可以得到不同的生成树,即使是同一种搜索方法,出发点不同亦可导致不同的生成树。 可以证明:具有n个顶点的带权连通图,其对应的生成树有n-1条边。 二、求图的最小生成树算法 严格来说,如果图G=(V,E)是一个连通的无向图,则把它的全部顶点V和一部分边E’构成一个子图G’,即G’=(V, E’),且边集E’能将图中所有顶点连通又不形成回路,则称子图G’是图G的一棵生成树。 对于加权连通图,生成树的权即为生成树中所有边上的权值总和,权值最小的生成树称为图的最小生成树。 求图的最小生成树具有很高的实际应用价值,比如下面的这个例题。

例1、城市公交网 [问题描述] 有一张城市地图,图中的顶点为城市,无向边代表两个城市间的连通关系,边上的权为在这两个城市之间修建高速公路的造价,研究后发现,这个地图有一个特点,即任一对城市都是连通的。现在的问题是,要修建若干高速公路把所有城市联系起来,问如何设计可使得工程的总造价最少。 [输入] n(城市数,1<=n<=100) e(边数) 以下e行,每行3个数i,j,w ij,表示在城市i,j之间修建高速公路的造价。 [输出] n-1行,每行为两个城市的序号,表明这两个城市间建一条高速公路。 [举例] 下面的图(A)表示一个5个城市的地图,图(B)、(C)是对图(A)分别进行深度优先遍历和广度优先遍历得到的一棵生成树,其权和分别为20和33,前者比后者好一些,但并不是最小生成树,最小生成树的权和为19。 [问题分析] 出发点:具有n个顶点的带权连通图,其对应的生成树有n-1条边。那么选哪n-1条边呢?设图G的度为n,G=(V,E),我们介绍两种基于贪心的算法,Prim算法和Kruskal算法。 1、用Prim算法求最小生成树的思想如下: ①设置一个顶点的集合S和一个边的集合TE,S和TE的初始状态均为空集; ②选定图中的一个顶点K,从K开始生成最小生成树,将K加入到集合S; ③重复下列操作,直到选取了n-1条边: 选取一条权值最小的边(X,Y),其中X∈S,not (Y∈S); 将顶点Y加入集合S,边(X,Y)加入集合TE; ④得到最小生成树T =(S,TE)

常用的大数据结构与算法

常用的大数据结构与算法 在学习了解这些数据结构和算法之前,引用一位前辈的话: “我们不需要你能不参考任何资料,实现红黑树;我们需要的是你能在实践当中,选择恰当的数据结构完成程序开发;在必要的时候,能在已有的数据结构基础上进行适当改进,满足工程需要。但要做到这一点,你需要掌握基础的算法和数据结构,你需要理解并应用一些高级数据结构和算法的思想。因此,在程序员这条道路上,你要想走得更远,你需要活用各种数据结构,你需要吸收知名算法的一些思想,而不是死记硬背算法本身。” 那么,工程实践当中,最常用的算法和数据结构有哪些? 以下是Google工程师Arjun Nayini在Quora给出的答案,得到了绝大多数人的赞同。 最常用的算法 1.图搜索算法(BFS,DFS) 2.排序算法 3.通用的动态规划算法 4.匹配算法和网络流算法 5.正则表达式和字符串匹配算法 最常用的数据结构 1.图,尤其是树结构特别重要 2.Maps结构 3.Heap结构 4.Stacks/Queues结构 5.Tries树 其他一些相对比较常用的数据算法还有:贪心算法、Prim’s / Kruskal’s算法、Dijkstra’s 最短路径算法等等。 怎么样才能活用各种数据结构? 你能很清楚的知道什么时候用hash表,什么时候用堆或者红黑色?在什么应用场景下,能用红黑色来代替hash表么?要做到这些,你需要理解红黑树、堆、hash表各有什么特性,彼此优缺点等,否则你不可能知道什么时候该用什么数据结构。 常言道: 程序=算法+数据结构 程序≈数据结构 小编希望这些算法的掌握能够帮助大家拓宽握数据结构和算法的视野,提高算法设计和动手编程的能力。

最小生成树的Kruskal算法实现

#include #include #define M 20 #define MAX 20 typedef struct { int begin; int end; int weight; }edge; typedef struct { int adj; int weight; }AdjMatrix[MAX][MAX]; typedef struct { AdjMatrix arc; int vexnum, arcnum; }MGraph; void CreatGraph(MGraph *);//函数申明 void sort(edge* ,MGraph *); void MiniSpanTree(MGraph *); int Find(int *, int ); void Swapn(edge *, int, int); void CreatGraph(MGraph *G)//构件图 { int i, j,n, m; printf("请输入边数和顶点数:\n"); scanf("%d %d",&G->arcnum,&G->vexnum); for (i = 1; i <= G->vexnum; i++)//初始化图{ for ( j = 1; j <= G->vexnum; j++) { G->arc[i][j].adj = G->arc[j][i].adj = 0; } } for ( i = 1; i <= G->arcnum; i++)//输入边和权值

{ printf("请输入有边的2个顶点\n"); scanf("%d %d",&n,&m); while(n < 0 || n > G->vexnum || m < 0 || n > G->vexnum) { printf("输入的数字不符合要求请重新输入:\n"); scanf("%d%d",&n,&m); } G->arc[n][m].adj = G->arc[m][n].adj = 1; getchar(); printf("请输入%d与%d之间的权值:\n", n, m); scanf("%d",&G->arc[n][m].weight); } printf("邻接矩阵为:\n"); for ( i = 1; i <= G->vexnum; i++) { for ( j = 1; j <= G->vexnum; j++) { printf("%d ",G->arc[i][j].adj); } printf("\n"); } } void sort(edge edges[],MGraph *G)//对权值进行排序{ int i, j; for ( i = 1; i < G->arcnum; i++) { for ( j = i + 1; j <= G->arcnum; j++) { if (edges[i].weight > edges[j].weight) { Swapn(edges, i, j); } } } printf("权排序之后的为:\n"); for (i = 1; i < G->arcnum; i++) {

相关文档
相关文档 最新文档