排序

1.手写代码
(1)快速排序

void QuickSort(int *a,int l,int r)
{
	int key = a[l];//哨兵元素
	int i = l,j = r;
	if(i<j){
		while(i<j){
			//从右到左寻找小于哨兵元素的元素
			while(i<j && a[j]>key) 
				--j;
			//将右边找到的小于哨兵元素的数放到基准左边
			if(i<j) 
				a[i++] = a[j];
			//从左到右寻找大于哨兵元素的元素
			while(i<j && a[i]<key) 
				++i;
			//将左边找到的小于哨兵元素的数放到基准右边
			if(i<j) a[j--] = a[i];
		}
		//此时i==j,为基准(key)的位置
		a[i] = key;
		QuickSort(a,l,i-1);
		QuickSort(a,i+1,r);
	}
}

(2)冒泡排序

void BubbleSort(int *a,int size)
{
	int i,j,tmp;
	char flag = 0;//记录比较时是否发生交换
	//size-1次遍历比较,i记录遍历次数(已经冒泡的数据个数)
	for(i=0;i<size-1;++i){
		flag = 0;
		//遍历比较未冒泡的数据
		for(j=0;j<size-1-i;++j){
			if(a[j]>a[j+1]){
				tmp = a[j];
				a[j] = a[j+1];
				a[j+1] = tmp;
				flag = 1;//发生交换
			}
		}
		//一次遍历未发生交换,说明未冒泡的数据两两之间是有序的,
		//即数据整体已有序,排序已完成
		if(0 == flag)
			break;
	}
}

(3)堆排序

/*
大顶堆:
1.元素的key值从0开始
2.某节点的	左子节点:Lkey=2*key+1 右子节点:Rkey=2*key+2
3.key值最大的非叶子节点的key值	(n/2-1)
*/
//调整堆
void adjustHeap(int *a,int i,int size)
{
	int tmp = a[i];//1.保存当前父节点
	int key;

	for(key=2*i+1;key<size;key=2*key+1)
	{	
		//2.求左右子节点中较大者的key
		if(key+1<size && a[key+1]>a[key])
			++key;

		//3.如果子节点大于父节点,更新父节点数据,继续往下调整
		if(a[key] > tmp){
			a[i] = a[key];
			i = key;//更新当前父节点key值	
		}else{
			break;
		}
	}
	//4.i为保存的起始父节点数据的最终key位置
	a[i] = tmp;
}

void swap(int *a,int *b)
{
	int tmp = *a;
	*a = *b;
	*b = tmp;
}

void HeapSort(int *a,int size)
{
	int i;
	//1、构造无序大顶堆
	for(i=size/2-1;i>=0;--i)
		//从key值最大非叶子节点(size/2-1)从下至上,从右至左调整堆结构
		adjustHeap(a,i,size);

	//2、交换堆顶元素与末尾元素,调整堆结构
	//堆顶是最大的
	for(i=size-1;i>=0;--i){
		//堆顶放到i处
		swap(&a[0],&a[i]);
		//调整i之前的元素
		adjustHeap(a,0,i);
	}
}

2、快排算法介绍
根据哨兵元素,用两个指针指向待排序数组的首尾,
首指针从前往后移动找到比哨兵元素大的,
尾指针从后往前移动找到比哨兵元素小的,
交换两个元素,直到两个指针相遇,这是一趟排序。

经过这趟排序后,比哨兵元素大的在右边,小的在左边。经过多趟排序后,整个数组有序。

稳定性:不稳定
平均时间复杂度:O(nlogn)

3.快排的时间复杂度最差是多少?什么时候时间最差?
时间复杂度最差O(N^2),元素本来倒序排列用时最多

4.稳定排序有哪几种?
冒泡排序、归并排序、基数排序、插入排序(直接插入排序、折半插入排序)

5.各种排序算法介绍及时间复杂度
在这里插入图片描述
1、冒泡排序:
从数组中第一个数开始,依次遍历数组中的每一个数,通过相邻比较交换,每一轮循环下来找出剩余未排序数的中的最大数并“冒泡”至数列的顶端。

稳定性:稳定
平均时间复杂度:O(n ^ 2)

2、插入排序:
从待排序的n个记录中的第二个记录开始,依次与前面的记录比较并寻找插入的位置,每次外循环结束后,将当前的数插入到合适的位置。

稳定性:稳定
平均时间复杂度:O(n ^ 2)

3、希尔排序(缩小增量排序):
希尔排序法是对相邻指定距离(称为增量)的元素进行比较,并不断把增量缩小至1,完成排序。
希尔排序开始时增量较大,分组较多,每组的记录数目较少,故在各组内采用直接插入排序较快,后来增量di逐渐缩小,分组数减少,各组的记录数增多,但由于已经按di−1分组排序,文件叫接近于有序状态,所以新的一趟排序过程较快。因此希尔 排序在效率上比直接插入排序有较大的改进。
在直接插入排序的基础上,将直接插入排序中的1全部改变成增量d即可,因为希尔排序最后一轮的增量d就为1。

稳定性:不稳定
平均时间复杂度:希尔排序算法的时间复杂度分析比较复杂,实际所需的时间取决于各次排序时增量的个数和增量的取值。时间复杂度在O(n ^ 1.3)到O(n ^ 2)之间。

4、选择排序:
从所有记录中选出最小的一个数据元素与第一个位置的记录交换;然后在剩下的记录当中再找最小的与第二个位置的记录交换,循环到只剩下最后一个数据元素为止。

稳定性:不稳定
平均时间复杂度:O(n ^ 2)

5、快速排序
1)从待排序的n个记录中任意选取一个记录(通常选取第一个记录)为分区标准;
2)把所有小于该排序列的记录移动到左边,把所有大于该排序码的记录移动到右边,中间放所选记录,称之为第一趟排序;
3)然后对前后两个子序列分别重复上述过程,直到所有记录都排好序。

稳定性:不稳定
平均时间复杂度:O(nlogn)

6、堆排序:
堆:
1、完全二叉树或者是近似完全二叉树。
2、大顶堆:父节点不小于子节点键值,小顶堆:父节点不大于子节点键值。左右孩子没有大小的顺序。
堆排序在选择排序的基础上提出的,步骤:

1、建立堆
2、删除堆顶元素,同时交换堆顶元素和最后一个元素,再重新调整堆结构,直至全部删除堆中元素。

稳定性:不稳定
平均时间复杂度:O(nlogn)

7、归并排序:
采用分治思想,现将序列分为一个个子序列,对子序列进行排序合并,直至整个序列有序。

稳定性:稳定
平均时间复杂度:O(nlogn)

8、计数排序:
思想:如果比元素x小的元素个数有n个,则元素x排序后位置为n+1。
步骤:
1)找出待排序的数组中最大的元素;
2)统计数组中每个值为i的元素出现的次数,存入数组C的第i项;
3)对所有的计数累加(从C中的第一个元素开始,每一项和前一项相加);
4)反向填充目标数组:将每个元素i放在新数组的第C(i)项,每放一个元素就将C(i)减去1。

稳定性:稳定
时间复杂度:O(n+k),k是待排序数的范围。

9、桶排序:
步骤:
1)设置一个定量的数组当作空桶子; 常见的排序算法及其复杂度:
2)寻访序列,并且把记录一个一个放到对应的桶子去;
3)对每个不是空的桶子进行排序。
4)从不是空的桶子里把项目再放回原来的序列中。
时间复杂度:O(n+C) ,C为桶内排序时间。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值