C语言--5种基本排序方法

本文深入讲解了五种基本排序算法:冒泡排序、选择排序、插入排序、归并排序及快速排序。通过代码实例,详细解析了每种算法的工作原理、时间复杂度以及递归与非递归实现方式。

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

冒泡排序

int main() {
	int a[10] = {3,1,4,5,6};
	for(int i = 1; i <= 4; i++) { //进行n-1趟
		//第i趟时从 a[0] 到 a[n-i-1] 都与它们下一个数比较 
		for(int j = 0; j < 5-i; j++) {
			if(a[j] > a[j+1]) { // 如果左边的数更大,则交换 a[j] 和 a[j+1] 
				int temp = a[j];
				a[j] = a[j+1];
				a[j+1] = temp;
			}
		}
	}
}

选择排序

总共需要进行 n 趟操作(1 ≤ i ≤ n),每趟操作选出待排序部分 【i,n】中最小的元素, 令其余 A[ i ] 交换,总复杂度为 O[ n² ] ,代码如下:

void selectSort() {
	for(int i = 1; i <= n; i++){
		int k = i;
		for(int i = 1; j <= n; j++) { //选出[i,n]中最小的元素,下标为k
			if(A[j] < A[k]) {
				k = j;
			}
		}
		int temp = A[i];  //交换 A[k] 与 A[i]
		A[i] = A[k];
		A[k] = temp;
	}
}

插入排序

从后往前枚举已有序部分来确定插入位置

const int maxn = 100010;
int A[maxn], n;
void insertSort() {
	for(int i = 1; i < n; i++) { //进行 n-1 趟排序
		int temp = A[i], j = i;  //temp临时存放 A[i],j从i开始往前枚举 
		while(j > 0 && temp < A[j-1]) {  //只要temp小于前一个元素A[j-1]
			A[j] = A[j-1];  //把 A[j-1] 后移一位至 A[j]
			j--; 
		} 
		A[j] = temp;  //插入位置为 j 
	}
}

归并排序

递归

const int maxn = 100;
//将数组A的[L1,R1]与[L2,R2]区间合并为有序区间(此处L2即为R1+1)
void merge(int A[], int L1, int R1, int L2, int R2) {
	int i = L1, j = L2;  //i指向A[L1],j指向A[L2]
	int temp[maxn], index = 0;  //temp临时存放合并后的数组,index为其下标
	while(i <= R1 && j <= R2) {
		if(A[i] <= A[j]) { //如果A[i]<=A[j]
			temp[index++] = A[i++]; //将A[i]加入序列temp 
		} else { //如果A[i]>A[j]
			temp[index++] = A[j++]; //将A[j]加入序列temp 
		}
	} 
	while(i <= R1) temp[index++] = A[i++];  //将[L1,R1]的剩余元素加入序列temp
	while(j <= R2) temp[index++] = A[j++];  //将[L2,R2]的剩余元素加入序列temp
	for(i=0; i < index; i++) {
		A[L1 + i] = temp[i];   //将合并后的序列赋值回数组A 
	}
}
//将array数组当前区间[left,right]进行归并排序
void mergeSort(int A[], int left, int right) {
	if(left < right) { //只要 left < right 
		int mid = (left + right) / 2;    //取中点
		mergeSort(A, left, mid);  //递归,将左子区间[left,mid]归并排序
		mergeSort(A, mid+1, right);  //递归,将右子区间[mid+1,right]归并排序
		merge(A, left, mid, mid+1, right);  //将左子区间和右子区间合并 
	}
}

非递归

数组的下标从1开始,(如果数组下标从0开始,修改最里层的for loop即可)

void mergeSort(int A[]) {
	// step为组内元素个数,step / 2为左子区间元素个数,注意等号可以不取
	for(int step = 2; step / 2 <= n; step *= 2) {
		//每step个元素一组,组内前step/2和后step/2个元素进行合并
		for(int i = 1; i <= n; i += step) {  //对每一组
			int mid = i + step / 2 - 1;  //左子区间元素个数为 step/2
			if(mid + 1 <= n) { //右子区间存在元素则合并
				//左子区间为[i,mid],右子区间为[mid+1,min(i+step-1, n]
				merge(A, i, mid+1, min(i+step-1, n)); 
			} 
		} 
	}   
} 

sort替换merge

假如题目中只要求给出归并排序每一趟结束时的序列,可用sort函数代替merge函数(只要时间允许)

void mergeSort(int A[]) {
	//step为组内元素个数, step/2 为左子区间元素个数,注意等号可不取
	for(int step = 2; step / 2 <= n; step *= 2) {
		//每step个元素一组,组内[i, min(i+step, n+1)]进行排序
		for(iny i = 1; i <= n; i += step) {
			sort(A + i, A + min(i + step, n + 1));
		} 
	}
	//此处可输出归并排序的某一趟结束的序列 
}

快速排序

//对区间[left,right]进行划分
int Partition(int A[], int left, int right) {
	int temp = A[left];  //将A[left]存放至临时变量temp
	while(left < right) { //只要left与right不相遇
		while(left < right && A[right] > temp) right--; //反复左移right
		A[left] = A[right];  //将A[right]挪到A[left]
		while(left < right && A[left] <= temp) left++;  //反复右移left
		A[right] = A[left];  //将A[left]挪到A[right]  
	} 
	A[left] = temp;  //把temp放到left与right相遇的地方
	return left;  //返回相遇的下标 
} 
//快速排序,left与right初值为序列首尾下标(例如 1 与 n)
void quickSort(int A[], int left, int right) {
	if(left < right) {  //当前区间的长度不超过1
		//将[left,right]按A[left]一分为二
		int pos = Partition(A, left, right);
		qucikSort(A, left, pos-1);  //对左子区间递归进行快速排序 
		quickSort(A, pos+1, right); //对右子区间递归进行快速排序 
	}
} 

快速排序算法当序列中元素的排列比较随机时效率最高,但是当序列中元素接近有序时,会达到最坏时间复杂度O(n²),产生这种情况的主要原因在于主元没有把当前区间划分为两个长度接近的子区间。可以随机选择一个主元,使用 stdlib.h 中的 srand函数随机生成一个数据。
srand()用法

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值