【数据结构】实验练习(三)

 K-Means聚类算法的实现

#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<math.h>
#include<time.h>

#define N 11
#define k 3

typedef struct{
	float x;
	float y;
}Point;

//判断每个点属于哪个簇 
int center[N];

Point point[N]={
	{2.0,10.0},
	{2.0,5.0},
	{8.0,4.0},
	{5.0,8.0},
	{7.0,5.0},
	{6.0,4.0},
	{1.0,2.0},
	{4.0,9.0},
	{7.0,3.0},
	{1.0,3.0},
	{3.0,9.0}
};

//保存每个簇的中心点
Point mean[k];

float getDistance(Point point1,Point point2){
	float d;
	d=sqrt((point1.x-point2.x)*(point1.x-point2.x)+(point1.y-point2.y)*(point1.y-point2.y));
	return d;
} 

//计算每个簇的中心点
void getMean(int center[N]){
	Point tep;
	int i,j,count=0;
	for(i=0;i<k;i++){
		count=0;
		tep.x=0.0;
		tep.y=0.0;
		for(j=0;j<N;++j){
			if(i==center[j]){
				count++;
				tep.x+=point[j].x;
				tep.y+=point[j].y;
			}
		}
		tep.x/=count;
		tep.y/=count;
		mean[i]=tep;				
	}
	for(i=0;i<k;++i){
		printf("The new center point of %d is:\t(%f,%f)\n",i+1,mean[i].x,mean[i].y);	
	}
} 

//计算平方误差函数
float getE(){
	int i,j;
	float cnt=0.0,sum=0.0;
	for(i=0;i<k;++i){
		for(j=0;j<N;++j){
			if(i==center[j]){
				cnt=(point[j].x-mean[i].x)*(point[j].x-mean[i].x)+(point[j].y-mean[i].y)*(point[j].y-mean[i].y);
				sum+=cnt;
			}
		}
	}
	return sum;
} 

//把N个点聚类
void cluster(){
	int i,j,q;
	float min;
	float distance[N][k];
	for(i=0;i<N;++i){
		min=999999.0;
		for(j=0;j<k;++j){
			distance[i][j]=getDistance(point[i],mean[j]);
			//printf("%f\n",distance[i][j]);用来测试对于每个点与3个中心点之间的距离 
		}
		for(q=0;q<k;++q){
			if(distance[i][q]<min){
				min=distance[i][q];
				center[i]=q;
			}
		} 
		printf("(%.0f,%.0f)\t in cluster-%d\n",point[i].x,point[i].y,center[i]+1);
	}
	printf("--------------------------\n");
} 

int main(){
	int i,j,n=0;
	float temp1;
	float temp2,t;
	printf("--------Data sets-------\n");
	for(i=0;i<N;++i){
		printf("\t(%.0f,%.0f)\n",point[i].x,point[i].y);
	}
	printf("--------------------------\n");
	/*	
	可以选择当前时间为随机数 
	stand((unsigned int)time(NULL));
	
	for(i=0;i<K;++i){
		j=rand()%k;
		mean[i].x=point[j].x;
		mean[i].y=point[j].y;	
	}

	*/
	//初始化k个中心点 
	mean[0].x=point[0].x;
	mean[0].y=point[0].y;	
		
	mean[1].x=point[3].x;
	mean[1].y=point[3].y;	
	
	mean[2].x=point[6].x;
	mean[2].y=point[6].y;
	
	cluster();	//第一次根据预设的k个点进行聚类 
	temp1=getE();	//第一次平方误差 
	n++;			//n计算形成最终的簇用了多少次 
	
	printf("The E2 is: %f\n\n",temp2);
	
	while(fabs(temp2-temp1)!=0){	//	比较两次平方误差 判断是否相等,不相等继续迭代 
		temp1=temp2;
		getMean(center);
		cluster();
		temp2=getE();
		n++;
		printf("The E%d is: %f\n",n,temp2);
	}
	printf("The total number of cluster is: %d\n\n",n);	//统计出迭代次数 
	system("pause"); 
	return 0;
} 
 

线性表的应用

实验目的:

1. 掌握线性表及其顺序存储与链式存储结构的概念;

2. 掌握两种存储方式的基本运算、实现方法和技术;

3. 灵活应用线性表进行程序设计,解决实际问题。

实验内容摘要:

编号为12....,NN个人按顺时针方向围坐一圈,每人持有一个密码(正整数)。一开始任选一个正整数作为报数上限值M,从第一个人开始按顺时针方向自1开始顺序报数,报到M时停止报数。报M的人出列,将他的密码作为新的M,从他在顺时针方向上的下一个人开始重新从1报数,如此下去,直至所有人全部出列为止。试设计一个程序求出出列顺序。利用单向循环链表存储结构模拟此过程,按照出列的顺序打印出每个人的编号。 

测试数据示例:

M的初值为6;N=7;7个人 的密码依次为:3,1,7,2,4,8,4 (正确的出列顺序应为6147235)

实验基本要求:

1. 写出完成实验内容的实验方法和源代码。

2. 写出实验数据及运行结果。

3. 写出在实验过程中所遇到的问题及解决办法。

实验过程及结果:

#include<stdio.h>
#include<malloc.h>
typedef struct LNode{
	int number,password;
	struct LNode *next;
}SLX;

struct LNode *head,*p,*pt;

int CreatListFunction(int n){
	int i;
	head=(struct LNode*)malloc(sizeof(SLX));
	p=head;
	for(i=1;i<n;i++){
		pt=(struct LNode*)malloc(sizeof(SLX));
		p->next=pt;
		p=pt;
	}
	p->next=head;
	pt=head;
	return 0;
}
int EnterPassword(int n){
	int i,k;
	printf("\n请输入密码:\n");
	for(i=1;i<=n;i++){
		scanf("%d",&k);
		pt->number=i;
		pt->password=k;
		pt=pt->next;
	}
	pt=p;
	return 0;
}
int OutListFunction(int m,int n){
	int i,a;
	for(i=1;i<=n;i++){
	 	for(a=1;a<m;a++){
	 		pt=pt->next;	
		}
		p=pt->next;
		m=p->password;
		printf("%d ",p->number);
		pt->next=p->next;
		free(p);
	}
	return 0;
}
int main(){
	int m,n;
	printf("\n参数m、n传递报数上限值和人数:\n");
	printf("\n请输入m和n:\n");
	scanf("%d %d",&m,&n);
	CreatListFunction(n);
	EnterPassword(n);
	printf("\n出队的人依次是:\n");
	OutListFunction(m,n);
	return 0;
}
#include<stdio.h>
#include<malloc.h>
typedef struct LNode{
	int number,password;
	struct LNode *next;
}SLX;

struct LNode *head,*p,*pt;

//创建循环空链表 
int CreatListFunction(int n){
	head=(struct LNode*)malloc(sizeof(SLX));
	p=head;
	for(int i=1;i<n;i++){
		pt=(struct LNode*)malloc(sizeof(SLX));
		pt->password=0;
		p->next=pt;
		p=pt;
	}
	p->next=head;
	pt=head;
	return 0;
}
//输入密码 
int EnterPassword(int n){
	int k;
	printf("\n请输入密码:\n");
	for(int i=1;i<=n;i++){
		scanf("%d",&k);
		pt->number=i;
		pt->password=k;
		pt=pt->next;
	}
	pt=p;
	return 0;
}
int OutListFunction(int m,int n){
	int i,a;
	for(i=1;i<=n;i++){
	 	for(a=1;a<m;a++){
	 		pt=pt->next;	
		}
		p=pt->next;
		m=p->password;
		printf("%d ",p->number);
		pt->next=p->next;
		free(p);
	}
	return 0;
}
int main(){
	int m,n;
	printf("\n参数m、n传递报数上限值和人数:\n");
	printf("\n请输入m和n:\n");
	scanf("%d %d",&m,&n);
	CreatListFunction(n);
	EnterPassword(n);
	printf("\n出队的人依次是:\n");
	OutListFunction(m,n);
	return 0;
}

二叉树的建立与遍历

实验目的:

1. 掌握二叉树的定义。

2. 二叉树的链式存储结构及在链式存储结构中三种遍历(前序,中序,后序)操作的实现及应用。

实验内容摘要:

1. 编写程序,建立一棵二叉树(以链表存储),对该二叉树进行遍历并输出该二叉树的前序,中序,后序遍历序列;

2. 编写程序,建立一棵二叉树(以链表存储),实现二叉树左右子树的交换;

3. 统计二叉树中叶子结点个数。

实验基本要求:

1. 写出完成实验内容的实验方法和源代码。

2. 写出实验数据及运行结果。

3. 写出在实验过程中所遇到的问题及解决办法。

实验过程及结果:

#include <stdio.h>
#include<stdlib.h>
#include<string.h>
//声明BTNode
typedef struct node{
	char data;
	struct node *lchild;
	struct node *rchild;
}BTNode;
//先序、中序建立二叉树 
BTNode *CreateBT1(char *pre,char *in,int n){
	BTNode *b;
	char *p;
	int k;
	if(n<=0) return NULL;
	b=(BTNode *)malloc(sizeof(BTNode));
	b->data=*pre;
	for(p=in;p<in+n;p++)
		if(*p==*pre)
			break;
		k=p-in;
		b->lchild=CreateBT1(pre+1,in,k);
		b->rchild=CreateBT1(pre+k+1,p+1,n-k-1);
	return b;
	
}
//先序、中序、后序遍历
void PreOrder(BTNode *b)
{	if(b!=NULL){
		printf("%c",b->data);
		PreOrder(b->lchild);
		PreOrder(b->rchild);
	}
} 
void InOrder(BTNode *b)
{	if(b!=NULL){
		PreOrder(b->lchild);		
		printf("%c",b->data);
		PreOrder(b->rchild);
	}
} 
void PostOrder(BTNode *b)
{	if(b!=NULL){
		PreOrder(b->lchild);
		PreOrder(b->rchild);
		printf("%c",b->data);
	}
} 
/*void CreateBTree(BTNode * &b,char *str)
{	BTNode *St[ MaxSize],*p;
	int top=-1,k,j=0;
	char ch;
	b=NULL;
	ch=str[j];
	while(ch!='/0')
	{	switch(ch)
		{	
			case '(':top++;St[top]=p;k=1;break;
			case ')':top--;break;
			case ',':k=2;break;
		default:p=(BTNode *)malloc(sizeof(BTNode));
			p->data=ch;
			p->lchild=p->rchild=NULL;
			if(b==NULL)
				b=p;
			else
			{
				switch(k)
				{	
					case 1:St[top]->lchild=p;break;
					case 2:St[top]->rchild=p;break;
				}
			}
		}
		j++;
		ch=str[j];
	}
}*/

查找与排序

实验目的:

1. 掌握基本查找和排序技术的原理及其实现方法;

2. 对于不同的要求,能选择比较合理的查找、排序算法,得到初步的算法分析的训练,提高算法设计的能力。

实验内容摘要:

定义一最大长度为20的结构体数组(可以在结构体中只定义关键字域),从键盘输入结构体数组各元素的关键字值,对该数组中的元素按关键字非递减的顺序进行排序,分别用插入排序,选择排序,冒泡排序,递归的快速排序方法完成,再用折半查找方法对已经有序的结构体数组进行操作,输入一待查记录关键字,根据查找情况输出相关信息,以上各功能模块均用函数实现。设计相应算法并分析各排序方法的效率。

该程序运行情况举例说明:

运行主界面如下图所示:提示用户输入相应选项,键入数字1则进行待排序数据值的输入;键入数字2直接插入排序;键入数字3进行直接选择排序;键入数字4则进行冒泡排序;键入数字5则进行递归的快速排序;键入数字6则进行折半查找;键入数字7显示元素序列;键入数字0程序退出。

#include<stdio.h>
#include<time.h>
#include <stdlib.h>
//#include<iostream>
#define OK 1
#define FALSE -1
//定义结构体数组
typedef struct{
	int array[30];//存储结构体数组中的元素 
	int len;//数组的长度 
}List;
//打印数组 
void Print(List *L){
	int i;
	//对于建立顺序表,我们首先确定要输入元素的个数,也就是L->len的长度,
	//然后以L->len的长度做for循环,对L->array[i]进行赋值操作。
	for(i=1;i<=L->len;i++){
		printf("%d ",L->array[i]);
	}
	printf("\n");
}
//初始化数组赋值
int InitList(List *L){
	int e,i;
	L->len=1;
	printf("请输入元素的值并以-1结束\n");
	for(i=1;i<=21;i++)
	{
		scanf("%d",&e);
		if(e==-1){
			L->len--;
			return OK;
		}else{
			L->array[i]=e;
			L->len++;
		}
		if(L->len>21){
			printf("最多只能输入20个数字!\n");
			printf("\n\n");//换行 
			L->len=20;
			return FALSE;
		}
	}
	return 0;
} 
//直接插入排序 
/*
void InsertSort(List *L){
	int i,j;
	for(i=2;i<=L->len;i++){
		int temp=L->array[i];
		for(j=i-1;temp<=L->array[j]&&j>=0;j--){
			L->array[j+1]=L->array[j];
		}
		L->array[j+1]=temp;
	} 
}
void InsertSort(List *L){
  	int i,j;
	for (i=2;i<=L->len;i++)
	{
	    if(L->array[i]<L->array[i-1])
	    {
		    L->array[0]=L->array[i];
		    for (j=i-1;L->array[j]>L->array[0];j--)
		    {
		        L->array[j+1]=L->array[j];
		    }
		    L->array[j+1]=L->array[0];		        
	    }
	}
}*/
//直接插入排序
//通过构建有序序列,对于未排序数据,在已排序序列中从后向前扫描,找到相应位置并插入。
void InsertSort(List L)
{
	int compare = 0;//关键字比较次数
	int remove = 0;//关键字移动次数
	int process = 1;//中间过程
	for (int i = 2;i <= L.len;i++)
	{
		compare++;
		if (L.array[i]< L.array[i-1])
		{
			L.array[0] = L.array[i];//设置哨兵
			L.array[i] = L.array[i - 1];
			int j = 0;
			for (j = i - 2;L.array[0] < L.array[j];j--)
			{
				L.array[j + 1] = L.array[j];//依次右移
			}
			L.array[j + 1] = L.array[0];//将哨兵插入合适的位置
			remove++;
		}
		//输出中间过程
		printf( "第%d次中间过程输出:",++process);
		for (int i = 1;i <= L.len;i++)
		{
			printf("%d ",L.array[i]);
		}
		printf("\n");

	}
	//输出关键字比较次数和关键字移动次数
	printf("关键字【比较】次数:%d\n",compare);
	printf("关键字【移动】次数:%d\n",remove);
	//Print(&L);
}
/*
//直接选择排序
void SelectSort(List *L){
	int i;
	for(i=0;i<L->len;i++){
		int temp=i;
		int j;
		for(j=i+1;j<L->len;j++){
			if(L->array[temp]>L->array[j])
				temp=j;
		}
		if(temp!=i){
			int index;
			index=L->array[temp];
			L->array[temp]=L->array[i];
			L->array[i]=index;
		}
	}
} */
//直接选择排序
//首先在未排序序列中找到最小(大)元素,存放到排序序列的起始位置。
//再从剩余未排序元素中继续寻找最小(大)元素,然后放到已排序序列的末尾。
//重复第二步,直到所有元素均排序完毕。
void SelectSort(List L)
{
	int k = 0;
	int compare = 0;//关键字比较次数
	int remove = 0;//关键字移动次数
	int process = 1;//中间过程
	for (int i = 1;i < L.len;i++)
	{
		k = i;
		for (int j = i+1;j <= L.len;j++)
		{
			compare++;
			if (L.array[j] < L.array[k])
			{
				k = j;//k:此趟排序中关键字最小记录
			}
		}
		if (k != i)//交换l[i]和l[k]
		{
			remove++;
			int temp = L.array[i];
			L.array[i] = L.array[k];
			L.array[k] = temp;
			//输出中间过程
			printf( "第%d次中间过程输出:",++process);
			for (int i = 1;i <= L.len;i++)
			{
				printf("%d ",L.array[i]);

			}
			printf("\n");
		}
	}
	//输出关键字比较次数和关键字移动次数
	printf("关键字【比较】次数:%d\n",compare);
	printf("关键字【移动】次数:%d\n",remove);
	//Print(&L);
}
/*冒泡排序
void BubbleSort(List *L){
	int i,j;
	for(i=0;i<L->len-1;i++){
		for(j=0;j<L->len-1;j++){
			if(L->array[j]>L->array[j+1]){
				int index=L->array[j];
				L->array[j]=L->array[j+1];
				L->array[j+1]=index;
			}	
		}
	}
} */
//冒泡排序
//比较相邻的元素。如果第一个比第二个大,就交换他们两个。
//对每一对相邻元素作同样的工作,从开始第一对到结尾的最后一对。这步做完后,最后的元素会是最大的数。
//针对所有的元素重复以上的步骤,除了最后一个。
void BubbleSort(List L)
{
	int compare = 0;//关键字比较次数
	int remove = 0;//关键字移动次数
	int process = 1;//中间过程
	int m = L.len;
	int flag = 1;//用于标记某一趟排序是否发生交换
	while (1)
	{
		flag = 0;//若本趟没有发生交换则结束排序
		for (int i = 0;i <= m;i++)
		{
			compare++;
			if (L.array[i] > L.array[i + 1])
			{
				flag = 1;
				int temp = L.array[i + 1];
				L.array[i + 1] = L.array[i];
				L.array[i] = temp;
				remove++;
			}
		}
		if (flag == 0)
		{
			break;
		}
 		//输出中间过程
		printf( "第%d次中间过程输出:",++process);
		for (int i = 1;i <= L.len;i++)
		{
			printf("%d ",L.array[i]);
		}
		printf("\n");
		--m;
	}
	//输出关键字比较次数和关键字移动次数
	printf("关键字【比较】次数:%d\n",compare);
	printf("关键字【移动】次数:%d\n",remove);
	//Print(&L);
}
/*//归并排序
void QiuckSort(int *a,int left,int right){
	int i=left;
	int j=right;
	int key=a[left];
	while(i<j){
		while(i<j&&key<=a[j])
			j--;
		a[i]=a[j];
		while(i<j&&key>=a[i])
			i++;
		a[j]=a[i];
	}
	a[i]=key;
	QiuckSort(a,left,i-i);
	QiuckSort(a,i+1,right);
} */
//快速排序
//从数列中挑出一个元素,称为 "基准"(pivot);
//重新排序数列,所有元素比基准值小的摆放在基准前面,所有元素比基准值大的摆在基准的后面(相同的数可以到任一边)。
//在这个分区退出之后,该基准就处于数列的中间位置。这个称为分区(partition)操作;
//递归地(recursive)把小于基准值元素的子数列和大于基准值元素的子数列排序;
int Qcompare = 0;//关键字比较次数
int Qremove = 0;//关键字移动次数
int Qprocess = 1;//中间过程
 
void QuickSort(List *L, int left, int right)
{	
	if (left >= right)
		return;			
	int pivot =L->array[left];
	int i = left, j = right;	
	while (i < j)
	{
		while (i < j && L->array[j] >= pivot)
		{
			j--;
			Qcompare++;
		}
		L->array[i] = L->array[j];		
		while (i < j && L->array[i] < pivot)
		{
			i++;
			Qcompare++;
		}			
		L->array[j] = L->array[i];
		Qremove++;
	}
	L->array[i] = pivot;
	//输出中间过程
	printf( "第%d次中间过程输出:",++Qprocess);
	for (int i = 1;i <= L->len;i++)
	{
		printf("%d ",L->array[i]);
	}
	printf("\n");
	QuickSort(L, left, i-1);
	QuickSort(L, i+1, right);	
}
/*int BinarySearch(List *L,int target){
	int left=0,right=L->len-1;
	while(left<=right){
		int mid=(right+left)/2;
		int num=L->array[mid];
		if(num==target)
			return mid;
		else if(num>target)
			right=mid-1;
		else 
			left=mid+1;
	}
	return -1;
} */
//二分查找 
int BinarySearch(List *L, int key) {
	int low, mid, high;
	low = 0;// 最小下标
	high = L->len - 1;// 最大小标
	while (low <= high) {
		mid = (high + low) / 2;// 折半下标
		int num=L->array[mid];
		if (key > num) {
			low = mid + 1; // 关键字比折半值大,则最小下标调成折半下标的下一位
		} else if (key < num) {
			high = mid - 1;// 关键字比折半值小,则最大下标调成折半下标的前一位
		} else {
			return mid; // 当 key == num 返回折半下标
		}
	}
	return -1;
}
int main(){
	List L;	
	//使用随机数生成数组 
	printf( "请输入数组的长度:");
	scanf("%d",&L.len);
	printf("随机生成的长度为%d的数组为:\n",L.len);
	srand(time(0));
	for (int i = 1;i <= L.len;i++)
	{
		L.array[i] = rand() % 90 + 10;
		printf( "%d ",L.array[i]);
	}	
	printf("\n");
	printf("初始序列为:\n");
	Print(&L);
	/*
	//自己输入待排序数组 
	InsertSort(&L);
	printf("输出序列为:");
	Print(&L);
	*/
	printf("*******************************\n");
	printf("select 1:输入待排序元素值\n");
	printf("select 2:直接插入排序\n");
	printf("select 3:直接选择排序\n");
	printf("select 4:冒泡排序\n");
	printf("select 5:递归的快速排序\n");
	printf("select 6:折半查找\n");
	printf("select 7:显示元素序列\n");
	printf("select 0:退出\n");
	printf("*******************************\n");
	int n; 
	int num,target;
	int flag=1;
	while (flag)
	{
		scanf("%d", &n);
		switch (n){
			case 1:
				target=InitList(&L);
				if(target==-1){
					printf("元素录入失败!\n");
					printf("退出!");
					flag=0;
				}else{
					printf("元素录入成功!\n");
					printf("初始序列如下:");
					Print(&L);
					printf("\n\n");//换行 	
				}
				break;
			case 2:
				InsertSort(L); 
				printf("排序成功!\n");
				printf("\n\n");//换行 
				break;
			case 3:
				SelectSort(L); 
				printf("排序成功!\n");
				printf("\n\n");//换行 
				break;
			case 4:
				BubbleSort(L); 
				printf("排序成功!\n");
				printf("\n\n");//换行 
				break;
			case 5:
				QuickSort(&L,1,L.len);
				printf("排序后的序列为:\n");		
				for (int i=1; i<=L.len; i++)
					printf("%d ", L.array[i]);
				printf("\n排序成功!\n");
				printf("\n\n");//换行 
				break;
			case 6:
				printf("请输入查找的数\n");
				scanf("%d",&num);
				target=BinarySearch(&L,num);
				if(target==-1) {
					printf("查找的数不存在\n"); 
				}else{
					printf("查找的数为数组的第 %d 个数\n",target); 
				}										
				printf("查找完成");
				printf("\n\n");//换行 
				break;
			case 7:
				printf("元素序列为:");
				Print(&L);
				printf("\n\n");//换行 
				break;
			case 0:
				printf("退出!");
				flag=0;
				break;
			default:
				printf("\n没有此选项,请重新选择!\n\n");
				break;
		}
	}
}
  • 25
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值