【数据结构】排序

update information

2019.12.19 总结 多一句口诀;补充了十大排序动画链接

总结

所属策略排序策略一句话总结时间复杂度稳定性
插入直接插入排序哨兵;后面往前面插O(n^2)稳定
插入希尔排序子表排序;设置增量O(n^2)【最坏情况下】不稳定
交换冒泡排序竖着写;底部开始依次交换O(n^2)稳定
交换快速排序分治,基准找位置O(n^2)不稳定
选择简单选择排序无序中找最小的和基准交换O(n^2)不稳定
选择堆排序大小根堆,反复调整O(nlog2n)不稳定
归并归并排序几种组合,最后合并O(nlog2n)稳定
基数基数排序LSD,MSD,桶排序,筛选O(d(n分配 + r收集))稳定

 

背诵口诀

稳定性

不稳定: 快选堆希(快速排序,选择排序,堆排序,希尔排序)
稳定: 插冒归基(插入排序,冒泡排序,归并排序,基数排序(桶排序))
 

具体细节

演示细节:动画展示各种排序算法

插入

插入排序

原理: 设置一个哨兵,然后往后循环挨个往前插入。
稳定: 插入前面的时候是从后往前插的肯定稳定。

void InsertSort(ElemType A[] , int n){
	for(int i = 2 ; i <= n ; i ++){
		if(A[i].key < A[i - 1].key){
			A[0] = A[i];	//	先把数字放在A[0]里面 
			for(int j = i - 1 ; A[0].key < A[j].key ; j --){	//	从后往前查找,如果有数字比它大,那就把数字往后移// 
				A[j + 1] = A[j];	 
			}
			A[j + 1] = A[0];	//	在这个位置上把数字插进去// 
		}
	}
} 

 

希尔排序

原理: 分组;增量
稳定性: 分组不同,顺序不同,所以不稳定。

void ShellSort(ElemType A[] , int n){
	for(int d = n / 2 ; d >= 1 ; d /= 2){	//	每次d的数值都是原先的1/2,但是最后一次必须得是1 
		for(int i = d + 1 ; i <= n ; i ++){	//	依次循环 
			if(A[i].key > A[i - d].key){
				A[0] = A[i];	//	相当于一个temp
				int j;
				for(j = i - d ; j > 0 && A[0].key < A[j].key ; j -= d){	//	确定移动的范围和长度 
					A[j + d] = A[j]; 
				} 
				A[j + d] = A[0];	//	多减了一个d的值 
			} 
		}
	}
} 

 

交换

冒泡排序

原理: 竖着写,底部累次交换.
稳定性: 底部交换,满足条件才换,所以稳定。


void BubbleSort(ElemType A[] , int n){
	for(int i = 0 ; i < n - 1 ; i ++){	//	只用循环n-1次,每次必有一个已经有序 
		bool flag = false;
		for(int j = n - 1 ; j > i ; j --){	//	[a , b]的数字个数是	b - a + 1 
			if(A[j - 1].key > A[j].key){
				ElemType temp = A[j].key;
				A[j].key = A[j - 1].key;
				A[j - 1].key = temp;
				flag = true;	//	出现过变动 
			}
		} 
		if(flag == false)	//	未出现过变动,则已经有序 
			return ;
	}
} 

 

快速排序

原理: 分治思想
稳定性: 中间涉及到交换,肯定不稳定。
必看文章:【普及一下】【实例讲解


int Part(ElemType A[] , int low , int high){
	ElemType pivot = A[low];
	while(low < high){
		while(low < high && A[high] >= pivot){
			high --;	//	从右边开始,碰到比轴小的就和轴换位置 
		}
		A[low] = A[high];
		while(low <high && A[low] <= pivot){
			low ++;	//	从左边开始,碰到比轴大的就和轴换位置 
		}
		A[high] = A[low];
	}
	A[low] = pivot;	//	当轴位置确定好之后,再去将数字放进去 
	return low;
} 

void QuickSort(ElemType A[] , int low , int high){
	int p = Part(A , low , high);
	QuickSort(A , low , p - 1);	//	前半部分 
	QuickSort(A , p + 1 , low);	//	后半部分 
}

 

选择

简单选择

原理: 无须列表中找有序的往前依次交换。
稳定性: 这个地方是交换,使得可能会把同样的换回来。(交换的时候不检查)

void SelectSort(ElemType A[] , int n){
	for(int i = 0 ; i < n - 1 ; i ++){	//	与冒泡排序类似,最后一个值最后自然可以确定 
		min = i;	
		for(int j = i + 1 ; j < n ; j ++){	//	从当前排序的后面找到一个最小值进行交换 
			if(A[j] < min)
				min = j;	//	先将下标保存 
		}
		if(min != i)	//	如果不是当前的数值,则swap 
			swap(A[i] , A[min]);
	}
} 

 

堆排序

原理: 作业调度,自下往上,检查从上至下。
特点: 堆排序最坏的情况下,时间复杂度也是O(nlogn)。而且对排序仅需要一个记录大小提供交换的辅助存储空间。

 

归并

归并排序

原理: 几组之间,互相组合,最后排序。
稳定性: 合并的时候顺序合并,使得可以稳定。

ElemType *B = (ElemType *)malloc((n + 1) * sizeof(*ElemType));
void Merge(ElemType A[] , int low , int mid , int high){
	for(int i = 0 ; i < high ; i ++){	//	将所有的数据放在这个辅助数组中 
		B[i] = A[i];
	}
	for(int i = low , j = mid + 1 , k = i ; i <= mid && j <= high ; k ++){	//	i和j分头开始搜索,当比另外一个大的时候就切换 
		if(B[i] <= B[j]){
			A[k] = B[i ++];
		}
		else{
			A[k] = B[j ++];
		}
	} 
	//	未填满的部分赋值下来
	while(i <= mid)		A[k ++] = A[i ++];	 
	while(j <= high)	A[k ++] = A[j ++];
} 

void MergeSort(ElemType A[] , int low , int high){
	if(low < high){
		int mid = (low + high) / 2;
		MergeSort(A , low , mid);	//	先对前半部分做排序 
		MergeSort(A , mid + 1 , high);	//	后半部分做排序 
		Merge(A , low , mid , high);	//	再将两个部分合并 
	}
}
  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值