算法设计与分析(第二版)上机实验题——C语言实现

算法设计与分析

    • 第一章
      • 实验1.统计求最大、最小元素的平均比较次数
      • 实验2.求无序序列中第k小的元素
      • 实验3.出队第k个元素
      • 实验4.设计一种好的数据结构
      • 实验5.设计一种好的数据结构
    • 第二章
      • 实验1.逆置单链表
      • 实验2.判断两棵二叉树是否同构
      • 实验5.求两个数最大公约数

第一章

实验1.统计求最大、最小元素的平均比较次数

代码如下:

#include 
#include 
#include 
int main() {
    int a[10],i,b,c,d=0,e,f;
    srand((unsigned)time(NULL));
	printf("有下列数字:");
    for (i = 0; i < 10; i++)
	{
	a[i] = rand()%20;
	printf("%d ",a[i]);
    }//这里是产生随机数,并且存储到数组里面去
	printf("\n");
	for(c=1;c<10;c++){
	d++;
	if(a[0]<a[c]){
	f=a[0];
	a[0]=a[c];
    a[c]=f;
   }
  }
 printf("最大值为:%d\n",a[0]);
  for(e=1;e<10;e++){
  d++;
  if(a[0]>a[e]){
    f=a[0];
    a[0]=a[e];
    a[e]=f;
   }
  }
 printf("最小值为:%d\n",a[0]);
 printf("比较次数为:%d\n",d);
     return 0;
}

运行结果如下:
在这里插入图片描述
解决方法:
所采用的是冒泡排序的循环比较,不过不需要排序,只需要找出最大值,最小值即可。用一个for循环,用第一个数和其他数进行比较,遇到大于第一个数的就进行值交换,直到比完最后一个数的时候,此时第一个数就是最大的,同理最小的也一样,碰到小于它的数就进行值交换。

实验2.求无序序列中第k小的元素

代码如下:

#include 
#include 
#include 
int main() {
    int i,b,c,d,e=0,f,k;
	int a[10];
	printf("输入的k值为:"); 
	scanf("%d",&k);
    srand((unsigned)time(NULL));
	printf("有下列数字:\n");
    for (i=0;i<=10;i++)
	{
	a[i] = rand()%100;
	printf("%d ",a[i]);
	}//这里是产生随机数,并且存储到数组里面去
	printf("\n");
	for(b=0;b<10;b++){
	  for(c=b+1;c<10;c++){
	   if(a[b]>a[c]){
	    d=a[b];
	    a[b]=a[c];
	    a[c]=d;
	  }
	}
  }
  printf("从小到大的顺序如下:\n");//题目并没有要求输出顺序的数字,我这里输出只是为了更好的观察,可以去掉输出排序后的数组代码
  for(f=0;f<10;f++){
  	printf("%d ",a[f]);
  }
  printf("\n");
  printf("第%d小的数字是:%d",k,a[k-1]);
     return 0;
}

运行结果如下:
算法设计与分析(第二版)上机实验题——C语言实现_第1张图片

解决方法:
用一个排序的方法将所有的数排序,从大到小或者从小到大都行,并且用数组存储起来,这样数组的第一个是最大或者最小,最后一个亦然,输出第k个数对应的数组序号即可这里要注意数组是从0开始的,我们是从第一个开始数的,所以要对数组内的数进行减一处理。

上面的代码有一点问题,就是无法排除相同数字在的排序。
例如下面:

算法设计与分析(第二版)上机实验题——C语言实现_第2张图片
这里第三小的数字应该为4,输出的却是2,是因为没有去除相同数字在的排序。下面的代码我采用了桶排序来解决这个问题,原理为:采用数组,利用数组下标来记录数字,数字为15对应的是数组a[15],当这个数字存在时,就把这个对应下标的数赋值为1,当后面仍存在相同的数时,仍然赋值为1,这样就去除了相同的数字。并且,这样也实现了排序,当统计完数字之后,就用for循环来判断值是否为1,为1则输出对应的下标。

#include
#include
#include
int main(){
	int a[1000],i,b,n,j=0,k,m[1000];
	for(i=0;i<1000;i++){
		a[i]=0;
	}
	scanf("%d",&n);
	srand((unsigned)time(NULL));
	printf("有下列%d个数字:\n",n);
    for(i=0;i<n;i++)
	{
	   b = rand()%100;
	   printf("%d ",b);
	   a[b]=1;
    }//这里是产生随机数,并把相对应的下标的数赋值为1
    printf("\n从小到大排序为(且无重复数字):\n");
   	for(i=0;i<1000;i++){
		if(a[i]==1){
			printf("%d ",i);
			m[j]=i;
			j++;
		}
	}
    printf("\nk=");
    scanf("%d",&k);
	printf("\n第%d小的数是:%d",k,m[k-1]);

	return 0;
}

运行结果如下:
算法设计与分析(第二版)上机实验题——C语言实现_第3张图片

这个代码是用空间换时间,你也可以用其他方法去除重复数字,比如,排完序之后,判断相邻的数是否相同,相同的话就把后面的数向前移动来覆盖掉这个数字。

实验3.出队第k个元素

代码如下:

#include
#include
typedef struct queue{//结构体来创建队列
	int data[100];
	int head=0;
	int tail=0;
}queue;
struct queue qu;//创建队列qu
struct queue another;//辅助队列
int main(){
	int i,k,n;
	printf("输入队列的大小为:");
	scanf("%d",&n);
	printf("输入队列的数为:\n"); 
	for(i=0;i<n;i++){
		scanf("%d",&qu.data[i]);//传数进入队列
		qu.tail++;//队尾后移
	}
	printf("k值为:");
	scanf("%d",&k);
	for(i=0;i<n;i++){
		if(qu.head!=k-1){//判断是否是第k个元素
			another.data[another.tail]=qu.data[qu.head];//把数传给辅助队列
			qu.head++;//qu队首往后移
			another.tail++;//辅助队列队尾后移,因为往里面传了数
		}
		else{
			printf("出队的是:%d",qu.data[qu.head]);//出队第k个元素
			qu.head++;
		}
	}
	qu=another;//将辅助队列赋值给主队列
	qu.head=0;
	printf("\n");
	printf("剩下的数为:\n");
	for(i=0;i<n-1;i++){
		printf("%d\n",qu.data[qu.head]);
		qu.head++;
	}
	return 0;
} 

执行结果如下:
算法设计与分析(第二版)上机实验题——C语言实现_第4张图片
思想:因为题目说出队,我就想到了队列,认为此题要用队列来做(其实也可以用其他来,只要符合题目要求即可)。这里我用了连个队列,一个辅助队列。先传数值进入队列,因为队列是先进先出,所以循环从第一个出队,并且把出队的传给辅助队列,直至到达第k个元素,第k个元素单独出队,并且不传给辅助队列,之后的也继续出队传给辅助队列,最后将辅助队列的数赋值给主队列,题目要求其余元素不变。
简单一点的话可以用数组来来实现

实验4.设计一种好的数据结构

编写一个实验程序,设计一种好的数据结构,尽可能高效地实现元素的插入、删除、按值查找和按序号查找(假设所有元素值不同)。

#include
#include
typedef struct queue{
	int data[100];
	int head=0;
	int tail=0;
}queue;
struct queue one;
//添加 
void add(queue &a,int b){
	a.data[a.tail]=b;
	a.tail++;
	printf("%d\n",b);
}
//按序号删除 
void del(queue &a,int b){
	int i;
	int j;
	j=a.tail-1;
	for(i=b;i<j;i++){
		a.data[i]=a.data[i+1];
	}
	a.tail++;
} 
//按序号查找
int sortNumber(queue &a,int b) {
	int temp;
	temp=a.data[b];
	return temp;
}
//按值查找(题意为没有重复的值,并且按值查找应该返回相应的序号)
int sortValue(queue &a,int b) {
	int i=0,temp;
	for(i;i<a.tail;i++){
		if(a.data[i]==b){
			temp=i;
			return temp+1;
		}
	}
	return -1; 
} 
int main(void){
	add(one,7);
	add(one,5);
	add(one,3);
	add(one,6);
	int a=sortNumber(one,2);
	printf("%d\n",a);
	int b=sortValue(one,2);
	printf("%d\n",b);
	del(one,7);
	printf("%d\n",one.data[one.head]);
}

思路:用数组模拟队列来实现这个数据结构,题目是说插入元素,我默认是按照插入队尾,所以用数组最好实现,数组也很方便的按照序号查找,另外也可以用链表来实现,数组也可以实现插入到中间,只是要把在那个元素后面的都要往后移,比链表麻烦一点。

实验5.设计一种好的数据结构

编写一个实验程序,设计一个好的数据结构,尽可能高效地实现下列功能:
1.插入若干个整数序列
2.获得该序列的中位数,中位数是指从小到大排序的中间的数,奇数序列只有一个,偶数序列有两个

#include
#include
typedef struct queue{
	int data[100];
	int head=0;
	int tail=0;
}queue;
struct queue one;
//添加 
void add(queue &a,int b){
	a.data[a.tail]=b;
	a.tail++;
	printf("%d\n",b);
}
void Middle(queue &a){
	int temp;
	int i=0,j;
	for(i;i<a.tail;i++){
		for(j=i+1;j<a.tail;j++){
			if(a.data[i]>a.data[j]){
				int c=0;
				c=a.data[i];
				a.data[i]=a.data[j];
				a.data[j]=c;
			}
		}
	}
	if(a.tail%2==0){
		printf("%d或者%d",a.data[(a.tail/2)-1],a.data[a.tail/2]);
	}else{
		printf("%d",a.data[a.tail/2]);
	}
} 
int main(void){
	add(one,7);
	add(one,5);
	add(one,3);
	add(one,6);
	add(one,1);
	Middle(one);
}

这里,我用实验4的数据结构,只采用了添加的函数,然后便编写了一个函数来对其进行排序以然后判断为奇数还是偶数序列,输出其对应的中位数。

第二章

实验1.逆置单链表

主要思路:递归。采用递归的方法进入到链表的最后一个节点,然后就从最后一个逆向翻转,也就是把链表尾部的变成表头,依次翻转

#include
typedef struct LNode{
	int val;
	struct LNode *next;
};
struct LNode *Inverted(struct LNode *&head){
	if(head==NULL||head->next==NULL){//判断临界条件,到链表尾部就返回
		return head;
	}
	struct LNode *temp=Inverted(head->next);//这里会一直往下延申直到最后一个节点
	head->next->next=head;//这里就是开始从尾部翻转
	head->next=NULL;
	return temp;
}

实验2.判断两棵二叉树是否同构

递归求解(深度优先遍历)

bool isSameTree(struct TreeNode* p, struct TreeNode* q){
	if(p==NULL&&q==NULL){
		return true;
	}else if(p==NULL||q==NULL){
		return false;
	}else if(p->data!=q->data){
		return false;
	}else{
		return isSameTree(p->left,q->left)&&isSameTree(p->right,q->right);
	}
}

实验5.求两个数最大公约数

#include 
// 辗转相除法
int Get(int x,int y){
	if(x%y==0){
		return y;
	}else{
		return Get(y,x%y);
	}
}
//等值算法
int Get1(int x,int y){
	if(x==y){
		return x;
	}else if(x>y){
		Get(y,x-y);
	}else{
		Get(x,y-x);
	}
}
int main() {
	int x=319;
	int y=377;
	printf("%d",Get(x,y));
	printf("%d",Get1(x,y));
	return 1;
}

第一种方法: 用辗转相除法求几个数的最大公约数,可以先求出其中任意两个数的最大公约数,再求这个最大公约数与第三个数的最大公约数,依次求下去,直到最后一个数为止。最后所得的那个最大公约数,就是所有这些数的最大公约数。
第二种方法: 以较大的数减较小的数,接着把所得的差与较小的数比较,并以大数减小数。继续这个操作,直到所得的减数和差相等为止。
这里想知道原理可以参看最大公约数

你可能感兴趣的:(算法,C语言,算法,c语言)