GUET 算法作业 高级数据结构及其应用(C语言)


题目

题目


第一题

维护小根堆性质

作业要求是维护小根堆性质,但是思想和维护大根堆性质都是一样的,只需要把大于小于符号换一下就可以。

维护大根堆性质伪代码:
在这里插入图片描述

维护小根堆性质代码:(有个swap交换函数,很简单,自己添加即可)

/**维护小根堆性质,算法时间复杂度:O(logn)
*输入:堆A,A的结点i,数组里堆元素的个数
*输出:从i向下满足堆存储要去的堆结构
**/
void Min_Heapify(int A[], int i, int heapsize){ 
    int l = 2*i;    
    int r = 2*i + 1;
    int smallest = i;

    if(l <= heapsize && A[l - 1] < A[i - 1] ){
        smallest = l;
    }
    else
		smallest = i;
    
    if(r <= heapsize && A[r - 1] < A[smallest - 1]){
        smallest = r;
    }

    if(smallest != i){
        swap(&A[i - 1],&A[smallest - 1]);
        Min_Heapify(A, smallest, heapsize);
    }
    
}

建大根堆

同上,换符号即可。

建大根堆伪代码如下:
在这里插入图片描述

建立小根堆代码:

/**建立小根堆
 * 输入:堆A,数组里堆元素的个数
 * 
**/
void Built_Min_Heap(int A[], int heapsize){ 
    int n = heapsize; 
    for(int i = n / 2; i > 0; i--)
        Min_Heapify(A, i, n);
    
}

堆排序

堆排序伪代码:
在这里插入图片描述
C语言实现堆排序:

/**堆排序
 * 输入:堆A,数组里堆元素的个数
 * 从大到小排序
 * 最坏情况下的时间复杂度:O(nlogn)
**/ 
void HeapSort(int A[], int heapsize){
    Built_Min_Heap(A, heapsize);
    for(int i = heapsize; i > 0; i--){
        swap(&A[i - 1], &A[0]);
        heapsize--;
        Min_Heapify(A, 1, heapsize);

    }
}

返回优先队列中优先级最高的元素

返回优先队列中优先级最高的元素伪代码:
在这里插入图片描述

C语言实现返回优先队列中优先级最高的元素:

/**返回优先队列中优先级最高的元素
 * 输入:堆A
 * 时间复杂度O(1)
**/
int Get_Min(int A[]){
    return A[0];
}

返回优先队列中优先级最高的元素并删除

返回优先队列中优先级最高的元素并删除伪代码:
在这里插入图片描述

C语言实现返回优先队列中优先级最高的元素并删除:

/**返回优先队列中优先级最高的元素,删除
 * 输入:堆A,数组里堆元素的个数
 * 时间复杂度:O(logn)
**/
int Extract_Min(int A[], int heapsize){
    int min = A[0];
    A[0] = A[heapsize - 1];
    heapsize--;
    Min_Heapify(A, 1, heapsize);
    return min;
}

提高元素优先级

提高元素优先级伪代码:
在这里插入图片描述
C语言实现提高元素优先级:

/**提高元素优先级
 * 输入:堆A,要提高的等级k,元素i
 * 时间复杂度:O(logn)
**/
void Decrease_Key(int A[], int i, int k){
    A[i] = k;
    while (i > 1 && A[i] < A[i/2]){
        swap(&A[i], &A[i/2]);
        i = i/2;
    }
    
}

添加新元素

添加新元素伪代码:
在这里插入图片描述

C语言实现添加新元素:

/**添加新元素
 * 输入:堆A,插入的元素key,数组里堆元素的个数
 * 时间复杂度:O(logn)
**/
void Insert(int A[], int key, int heapsize){
    heapsize++;
    A[heapsize - 1] = 100000000; //最后的位置插入正无穷
    Decrease_Key(A, heapsize - 1, key);
}

主函数

int main(){
    int a[10] = {6,8,1,2,4,3,9,16,22,5};

    int  i,heapsize=10;
	printf("\n堆中的元素是------------------\n");
	for (i = 0; i < heapsize; i++) //输入堆中元素
		printf("%d   ", a[i]);

    //建立最小堆
	printf("\n最小堆------------------\n");
	Built_Min_Heap(a,heapsize);    
	for (i = 0; i < heapsize; i++)
		printf("%d ", a[i]);  //输出

    //返回优先队列中优先级最小的元素
	printf("\n优先队列中优先级最小的元素是:%d\n",Get_Min(a));

    Extract_Min(a,heapsize);
	printf("\n调用后Extract_Min的最小堆:\n");
	for (i = 0; i < heapsize-1; i++)
		printf("%d ", a[i]);   //输出结果
	printf("\n");

    //插入7
	Insert(a, 7, heapsize-1);  
	
	printf("插入7后的最小堆\n");
	for (i = 0; i < heapsize; i++)
		printf("%d   ", a[i]);   //输出结果

	printf("\n插入7后的堆排序\n");
	HeapSort(a, heapsize);
	for (i = 0; i < heapsize; i++)
		printf("%d   ", a[i]);   //输出结果
		return 0;

}

第二题

注释写得很详细,就不再细说。

#include<stdio.h>
#define N 999
#define NUM 10
//元素的数据结构
struct Node{
    struct S *head;
    struct Node *next;
    int nnum; //元素名字
};

//集合的数据结构
struct S{
    struct Node *head;
    struct Node *tail;
    int length; //集合内的元素个数(链表长度)
    int num; //集合名字
};

struct S s[N]; //集合数组
struct Node node[N];//集合内元素数组
int i = 1;
/**建立一个只包含元素x的新单点集**/
void Make_Set(struct Node *x){
    x->head = &s[i];
    x->next = NULL;
    x->nnum = i;
    s[i].tail = x;
    s[i].head = x;
    s[i].num = i;
    s[i].length = 1; //每一个单点集的长度都是‘1’
    i++;
}

/**并集替换**/
void Union(struct S *x,struct S *y){

        x->length = x->length + y->length;
        //实现中间部分断开且连接
        x->tail->next = y->head;

        //实现上部分断开且连接
        while (y->head != NULL ){
            y->head->head = NULL;
            y->head->head = x;
            y->head = y->head->next;
        }
            y->head = NULL;

        //实现下部分断开且连接
        x->tail = NULL;
        x->tail = y->tail;
        y->tail = NULL;

}

/**只允许小集合并到大集合里面,所以要保证大集合在的Union参数在小集合参数的前面**/
void Unions(struct S *x,struct S *y){
    if(x->length >= y->length)
        Union(x,y);
   else
        Union(y,x);
}

/**寻找包含元素x的集合名字**/
int Find(struct Node *x){
    int flag = 0;
    for (int i = 0; i < NUM; i++){
       while (s[i].head !=  NULL)
       {
           if(s[i].head->nnum == x->nnum){
               return s[i].num; //找到名字并返回
               flag = 1;
           }

            s[i].head = s[i].head->next;

       }
    }
    if (flag == 0){
        printf("没有该元素!\n");
    }


}

/**打印函数**/
void MyPrint(){
    printf("head  leth\n");
    for (int  j = 1; j <= NUM; j++){
        if(s[j].head != NULL)//判断集合是否为空,如果是空集合就不打印
            printf("  %d   %d\n",s[j].num, s[j].length);
    }
}

int main(){
    int n;
    for(int i = 1; i <= NUM; i++)
    {
        Make_Set(&node[i]); //创建单点集合
    }
    //合并单点集2和单点集合3
    Unions(&s[2],&s[3]);
    //合并单点集2和单点集合5
    Unions(&s[2],&s[5]);
    //合并单点集7和单点集合8
    Unions(&s[7],&s[8]);
    //合并单点集7和单点集合10
    Unions(&s[7],&s[10]);

    MyPrint();
    printf("请输入要找的结点名字:");
    scanf("%d",&n);
    printf("\n结点%d在集合%d里",n,Find(&node[n]));
    return 0;
}


第三题

注:prim算法并未完全实现,只有思路
prim算法伪代码:
在这里插入图片描述

C语言实现prim算法:

#include<stdio.h>
/**维护小根堆性质,算法时间复杂度:O(logn)**/
void Min_Heapify(int A[], int i, int heapsize){ 
    int l = 2*i;    
    int r = 2*i + 1;
    int smallest = i;

    if(l <= heapsize && A[l] < A[i] ){
        smallest = l;
    }
    else
		smallest = i;
    
    if(r <= heapsize && A[r] < A[smallest]){
        smallest = r;
    }

    if(smallest != i){
        swap(A[i],A[smallest]);
        Min_Heapify(A, smallest, heapsize);
    }
    
}

/**返回优先队列中优先级最高的元素,删除**/
int Extract_Min(int A[], int heapsize){
    int min = A[1];
    A[1] = A[heapsize - 1];
    heapsize--;
    Min_Heapify(A, 1, heapsize);
    return min;
}
/**提高元素优先级**/
void Decrease_Key(int A[], int i, int k){
    A[i] = k;
    while (i > 1 && A[i] < A[i/2]){
        swap(&A[i], &A[i/2]);
        i = i/2;
    }
    
}
//book数组用来记录哪些顶点已经放入生成树中 
int dis[7], book[7] = {0};
    
//h数组用来保存堆,pos数组用来存储每个顶点在堆中的位置,heapsize为堆的大小 
int h[7], pos[7], heapsize; 

//交换函数,用来交换堆中的两个元素的值 
void swap(int x,int y)
{
	int t;
	t=h[x];
	h[x]=h[y];
	h[y]=t;
	//同步更新pos 
	t=pos[h[x]];
	pos[h[x]]=pos[h[y]];
	pos[h[y]]=t;
} 

int main(){ 

    int inf = 99999999;
   
    //count用来记录生成树中顶点的个数,sum用来记录存储路径之和 
	int count=0, sum=0;
    
    //将1号顶点加入生成树,book数组来标记一个顶点是否已经加入生成树 
	book[1] = 1;
	count++;
    int n, m, i, j,k;
	int u[19], v[19], w[19], first[7], next[19];

	//读入n和m,n表示顶点个数,m表示边的条数 
    printf("请输入顶点数和边数:");
	scanf("%d %d",&n,&m);

	//开始读入边 
	for(i = 1; i <= m; i++)
	{
		scanf("%d%d%d",&u[i] ,&v[i] ,&w[i]);
	}

	//这里是无向图,所以需要将所有的边再反向存储一次 
	for(i = m + 1; i <= 2*m; i++)
	{
		u[i] = v[i-m];
		v[i] = u[i-m];
		w[i] = w[i-m];
	}

	//开始使用邻接表存储边 
	for( i= 1; i <= n; i++)
	{
		first[i] = -1;
	}
	for(i = 1; i <= 2*m; i++)
	{
		next[i] = first[u[i]];
		first[u[i]] = i;
	}

	//初始化dis数组,这里是1号顶点到其余各个顶点的初始距离 
	dis[1] = 0;
	for(i = 2; i <= n; i++)
	{
		dis[i] = inf;
	}
	k = first[1];
	while(k != -1)
	{
		dis[v[k]] = w[k];
		k = next[k];
	} 

	//初始化堆 
	heapsize = n;
	for(i = 1; i <= heapsize; i++)
	{
		h[i] = i;
		pos[i] = i;
	}
	for(i = heapsize/2; i >= 1; i--)
	{
		Min_Heapify(h,i,heapsize);
	}
        
	//先弹出一个堆顶元素,因为此时堆顶是1号顶点 
	Extract_Min(h,heapsize);
	while(count < n)
	{
		j = Extract_Min(h,heapsize);
		book[j] = 1;
		count++;
		sum = sum + dis[j];
		//扫描当前顶点j所有的边,再以j为中间结点,更新生成树到每一个非树顶点的距离
		k = first[j];
         
		while(k != -1)
		{
			if(book[v[k]] == 0 && dis[v[k]] > w[k])
			{
                //更新距离 
				dis[v[k]] = w[k];
				//pos[v[k]]存储的是顶点v[k]在堆中的位置 
				Decrease_Key(h,pos[v[k]], w[k]); 
			}
			k = next[k];
		}
	}
    printf("最短路径长度为:%d",sum);
    return 0;
}

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值