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. 灵活应用线性表进行程序设计,解决实际问题。
实验内容摘要:
编号为1,2,....,N的N个人按顺时针方向围坐一圈,每人持有一个密码(正整数)。一开始任选一个正整数作为报数上限值M,从第一个人开始按顺时针方向自1开始顺序报数,报到M时停止报数。报M的人出列,将他的密码作为新的M值,从他在顺时针方向上的下一个人开始重新从1报数,如此下去,直至所有人全部出列为止。试设计一个程序求出出列顺序。利用单向循环链表存储结构模拟此过程,按照出列的顺序打印出每个人的编号。
测试数据示例:
若M的初值为6;N=7;7个人 的密码依次为:3,1,7,2,4,8,4 (正确的出列顺序应为6,1,4,7,2,3,5)。
实验基本要求:
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;
}
}
}