数据结构--C语言--排序算法的实现--插入排序,希尔排序,冒泡排序,快速排序,简单选择排序,堆排序

本文深入讲解了各种排序算法的实现,包括直接插入排序、希尔排序、冒泡排序、快速排序、简单选择排序、堆排序和归并排序。通过具体代码示例,详细解析了每种算法的工作原理和时间复杂度分析。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

排序算法的实现必做,验证性实验,4学时)

  1. 实验目的

熟悉排序的方法、过程及原则。掌握插入排序、快速排序、选择排序、归并排序的算法思想及实现方法,掌握其时间复杂度的分析方法。

  1. 实验内容

定义待排序序列的存储结构。验证插入排序、希尔排序、冒泡排序、快速排序、简单选择排序、堆排序、归并排序中各排序方法中的一、二个排序算法。

  1. 插入类排序:直接插入排序、希尔排序
  2. 交换类排序:冒泡排序、快速排序
  3. 选择类排序:简单选择排序、堆排序
  4. 归并类排序:递归和非递归形式的归并排序(归并排序在下面的博客里会发,这一个就先不发了)

各个函数如下,整体可运行的代码在最后。

直接插入排序

void InsertSort(SqList &L){
	int i,j;
	for(i=2;i<=L.length;i++){
		if(LT(L.base[i],L.base[i-1])){//逆序 需要移动 
			L.base[0] = L.base[i];//设置岗哨
			L.base[i] = L.base[i-1];
			for(j=i-2;LT(L.base[0],L.base[j]);j--)
				L.base[j+1] = L.base[j];
			L.base[j+1] = L.base[0];
		}
	}
}

希尔排序

void ShellInsert(SqList &L,int dk){//进行一次增量为dk的希尔排序
	int i,j;
	for(i=1+dk;i<=L.length;i++){
		if(L.base[i],L.base[i-dk]){//从后向前依次比较 
			L.base[0] = L.base[i];
			for(j=i-dk;j>0&&LT(L.base[0],L.base[j]);j-=dk)
				L.base[j+dk] = L.base[j];
			L.base[j+dk] = L.base[0];
		}
	}
}

void ShellSort(SqList &L,int dlta[],int t){//dlta[]数组里存放的是需要进行希尔排序的增量 t是dlta的表长 
	for(int k=0;k<t;k++)
		ShellInsert(L,dlta[k]);//一趟增量为dlta[k]的插入排序 
}

 冒泡排序

void Bubble_Sort(SqList &L){
	int change = true;
	for(int i=1;i<=L.length-1&&change;i++){//n-1趟 如果内循环进行完了之后没有进行一次交换 说明后面都是有序的不需要再排序了可以直接退出 
		change = false;
		for(int j=1;j<=L.length-i;j++){
			L.base[0] = L.base[j+1];
			if(L.base[j]>L.base[j+1]){
				L.base[j+1] = L.base[j];
				L.base[j] = L.base[0];
				change = true;
			}
		}
	}
}

 快速排序

int Partition(SqList &L,int low,int high){//进行一次交换的函数 
	L.base[0] = L.base[low];//一般用子表的第一个记录作为枢轴 
	while(low<high){//low=high跳出循环 从表的两端交替的向中间扫描 
		while(low<high&&L.base[high]>=L.base[0]) high--;
		L.base[low] = L.base[high];//将比枢轴记录小的记录移到低端 
		while(low<high&&L.base[low]<=L.base[0]) low++;
		L.base[high] = L.base[low];//将比枢轴记录大的记录移到高端 
	}
	L.base[low] = L.base[0];//枢轴记录到位 
	return low;
}

void QSort(SqList &L,int low,int high){
	if(low<high){
		int pivotloc = Partition(L,low,high);//因为Partition()函数并没有将low和high的值的改变带回 所以low和high都是原值 
		QSort(L,low,pivotloc-1);//对低字表递归排序 pivotloc是枢轴记录所在位置 
		QSort(L,pivotloc+1,high);//对高字表递归排序
	}
}

 简单选择排序

void SelectSort(SqList &L){
	int min;
	for(int i=1;i<=L.length-1;i++){
		min = i;
		L.base[0] = L.base[i];//备份 
		for(int j=i+1;j<=L.length;j++)
			if(L.base[j]<L.base[min]) min = j;
		if(i!=min){
			L.base[i] = L.base[min];
			L.base[min] = L.base[0];
		}
	}
}

堆排序

void HeadAdjust(SqList &L,int s,int m){//假设除了根之外的序列都是有序的 那么对根做一次筛选 使其插入在合适的位置 整体有序
	L.base[0] = L.base[s];
	for(int i=2*s;i<=m;i*=2){
		if(i<m&&LT(L.base[i],L.base[i+1])) i++;//i停在子树里最大的孩子上
		if(LT(L.base[i],L.base[0])) break;//根大于两个孩子里最大的 则这个子树是大根堆 不需要再作调整 
		L.base[s] = L.base[i];//孩子里数值大的上去做根 
		s = i; //s永远指向大根堆的根
	}
	L.base[s] = L.base[0];//插入 
} 

void HeadSort(SqList &L){
	for(int i=L.length/2;i>0;i--) HeadAdjust(L,i,L.length);//把L.base[1...H.length]建成大根堆
	for(int i=L.length;i>1;i--){
		printf("%d ",L.base[1]);//输出堆顶元素 
		L.base[0] = L.base[1];//将堆顶记录和当前序列里的最后一个元素交换 
		L.base[1] = L.base[i];
		L.base[i] = L.base[0];
		HeadAdjust(L,1,i-1);//只有堆顶元素相对于子树来说无序 其余子树均是有序序列 只需要调用HeadAdjust算法重新调整1~i-1有序即可 i可无视掉 
	} 
}

整体可运行的代码,main函数里调用不同的函数,使用不同的方法排序,但是注意要将别的排序注释掉,一次只能用一个。 

 

#include<stdio.h>
#include<stdlib.h>

#define OK 1
#define ERROR 0
#define true 1
#define false 0
#define LIST_INIT_SIZE 50
#define LISTINCREMENT 10
#define LT(a,b) a<b
#define EQ(a,b) a==b
#define LQ(a,b) a<=b
#define NULLKEY -111

typedef int ElemType;
typedef int Status;

typedef struct{
	ElemType *base;
	int length;
	int listsize;
}SqList;

Status InitSqlist(SqList &L){
	L.base = (ElemType *)malloc(LIST_INIT_SIZE*sizeof(ElemType));
	if(!L.base) exit(-1);
	L.length = 0;
	L.listsize = LIST_INIT_SIZE;
}

Status CreatSqlist(SqList &L){
	InitSqlist(L); 
	int i=1;
	printf("请输入元素 输入-111意为停止:\n");
	scanf("%d",&L.base[i]);
	while(L.base[i]!=NULLKEY){
		i++;
		scanf("%d",&L.base[i]);
	}
	L.length = --i;
	return 0;
}

void InsertSort(SqList &L){
	int i,j;
	for(i=2;i<=L.length;i++){
		if(LT(L.base[i],L.base[i-1])){//逆序 需要移动 
			L.base[0] = L.base[i];//设置岗哨
			L.base[i] = L.base[i-1];
			for(j=i-2;LT(L.base[0],L.base[j]);j--)
				L.base[j+1] = L.base[j];
			L.base[j+1] = L.base[0];
		}
	}
}

void ShellInsert(SqList &L,int dk){
	int i,j;
	for(i=1+dk;i<=L.length;i++){
		if(L.base[i],L.base[i-dk]){//从后向前依次比较 
			L.base[0] = L.base[i];
			for(j=i-dk;j>0&&LT(L.base[0],L.base[j]);j-=dk)
				L.base[j+dk] = L.base[j];
			L.base[j+dk] = L.base[0];
		}
	}
}

void ShellSort(SqList &L,int dlta[],int t){//dlta[]数组里存放的是需要进行希尔排序的增量 t是dlta的表长 
	for(int k=0;k<t;k++)
		ShellInsert(L,dlta[k]);//一趟增量为dlta[k]的插入排序 
}

void Bubble_Sort(SqList &L){
	int change = true;
	for(int i=1;i<=L.length-1&&change;i++){//n-1趟 如果内循环进行完了之后没有进行一次交换 说明后面都是有序的不需要再排序了可以直接退出 
		change = false;
		for(int j=1;j<=L.length-i;j++){
			L.base[0] = L.base[j+1];
			if(L.base[j]>L.base[j+1]){
				L.base[j+1] = L.base[j];
				L.base[j] = L.base[0];
				change = true;
			}
		}
	}
}


int Partition(SqList &L,int low,int high){//进行一次交换的函数 
	L.base[0] = L.base[low];//一般用子表的第一个记录作为枢轴 
	while(low<high){//low=high跳出循环 从表的两端交替的向中间扫描 
		while(low<high&&L.base[high]>=L.base[0]) high--;
		L.base[low] = L.base[high];//将比枢轴记录小的记录移到低端 
		while(low<high&&L.base[low]<=L.base[0]) low++;
		L.base[high] = L.base[low];//将比枢轴记录大的记录移到高端 
	}
	L.base[low] = L.base[0];//枢轴记录到位 
	return low;
}

void QSort(SqList &L,int low,int high){
	if(low<high){
		int pivotloc = Partition(L,low,high);//因为Partition()函数并没有将low和high的值的改变带回 所以low和high都是原值 
		QSort(L,low,pivotloc-1);//对低字表递归排序 pivotloc是枢轴记录所在位置 
		QSort(L,pivotloc+1,high);//对高字表递归排序
	}
}

void SelectSort(SqList &L){
	int min;
	for(int i=1;i<=L.length-1;i++){
		min = i;
		L.base[0] = L.base[i];//备份 
		for(int j=i+1;j<=L.length;j++)
			if(L.base[j]<L.base[min]) min = j;
		if(i!=min){
			L.base[i] = L.base[min];
			L.base[min] = L.base[0];
		}
	}
}

void Visit(SqList L){
	printf("\n");
	for(int i=1;i<=L.length;i++){
		printf("%d ",L.base[i]);
	}
}

void HeadAdjust(SqList &L,int s,int m){
	L.base[0] = L.base[s];
	for(int i=2*s;i<=m;i*=2){
		if(i<m&&LT(L.base[i],L.base[i+1])) i++;//i停在子树里最大的孩子上
		if(LT(L.base[i],L.base[0])) break;//根大于两个孩子里最大的 则这个子树是大根堆 不需要再作调整 
		L.base[s] = L.base[i];//孩子里数值大的上去做根 
		s = i; //s永远指向大根堆的根
	}
	L.base[s] = L.base[0];//插入 
} 

void HeadSort(SqList &L){
	for(int i=L.length/2;i>0;i--) HeadAdjust(L,i,L.length);//把L.base[1...H.length]建成大根堆
	for(int i=L.length;i>1;i--){
		printf("%d ",L.base[1]);//输出堆顶元素 
		L.base[0] = L.base[1];//将堆顶记录和当前序列里的最后一个元素交换 
		L.base[1] = L.base[i];
		L.base[i] = L.base[0];
		HeadAdjust(L,1,i-1);//只有堆顶元素相对于子树来说无序 其余子树均是有序序列 只需要调用HeadAdjust算法重新调整1~i-1有序即可 i可无视掉 
	} 
}

int main(){
	SqList L;
	int dlta[3]={5,3,1};
	
	CreatSqlist(L);
	printf("\n排序前的结果:");
	Visit(L);
	
//	printf("\n直接插入排序后的结果:");
//	InsertSort(L);

//	printf("\n希尔排序后的结果:");
//	ShellSort(L,dlta,3);

//	printf("\n冒泡排序后的结果:");
//	Bubble_Sort(L);

//	printf("\n快速排序后的结果:");
//	QSort(L,1,L.length);

//	printf("\n简单选择排序后的结果:");
//	SelectSort(L);

	Visit(L);
	
	printf("\n堆排序后的结果:");
	HeadSort(L);
	
	return OK; 

}

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值