第五讲:排序(复杂排序)

简单排序传送门

👉 简单排序

归并排序

传送门👉 归并排序

堆排序

传送门👉 堆排序

希尔排序

希尔排序可以说是直接插入排序的进阶版

基本思想
先取一个小于n的整数d1作为第一个增量,把文件的全部记录分组。所有距离为d1的倍数的记录放在同一个组中。先在各组内进行直接插入排序;然后,取第二个增量d2<d1重复上述的分组和排序,直至所取的增量 =1( < …<d2<d1),即所有记录放在同一组中进行直接插入排序为止。

该方法实质上是一种分组插入方法
比较相隔较远距离(称为增量)的数,使得数移动时能跨过多个元素,则进行一次比较就可能消除多个元素交换。D.L.shell于1959年在以他名字命名的排序算法中实现了这一思想。算法先将要排序的一组数按某个增量d分成若干组,每组中记录的下标相差d.对每组中全部元素进行排序,然后再用一个较小的增量对它进行,在每组中再进行排序。当增量减到1时,整个要排序的数被分成一组,排序完成。
一般的初次取序列的 一半为增量,以后每次减半,直到增量为1。

一个具体例子:
在这里插入图片描述
第一趟:
在这里插入图片描述
第二趟:
在这里插入图片描述
第三趟:
在这里插入图片描述
此躺不会影响上一趟已排好序列

代码:

void shell_sort(int a[], int n)
{
	int d, j, k;
	int t;
	
	for(d = n / 2; d > 0; d /= 2) // 其实就是将 0 的地方全部改成 d
	{
		for(j = d; j < n; j++)
		{
			t = a[j];
			for(k = j - 1; k >= d && a[k - d] > t; k--)
				a[k] = a[k - d];
			
			a[k] = t;
		} 
	}
} 

① 时间复杂度:O(n^(1.3—2))
② 希尔排序为不稳定排序

快速排序

基本思想
通过一趟排序将要排序的数据分割成独立的两部分,其中一部分的所有数据都比另外一部分的所有数据都要小,然后再按此方法对这两部分数据分别进行快速排序,整个排序过程可以递归进行,以此达到整个数据变成有序序列。

在这里插入图片描述
选择一个基准点,一般选择区间最左端元素(上图选择的是区间最右端)

设置 右、左 指针,分别从 右端、左端 开始 假如 右指针 指向的元素 大于等于 基准 点,则 右指针 向左移动,否则停止 接下来 假如 左指针 指向的元素 小于等于 基准点,则 左指针 向右移动,否则停止 (为了确保 左边部分总是小于等于基准点,右部分总是大于等于基准点

右指针、左指针 指向的元素相互交换,继续执行 第②步。 直到右指针 与 左指针 重合

将此时 两个指针所共同指向的元素基准点 相互交换

接下来是递归操作:以 两个指针共同指向的位置 作为 分界线; 前后两个部分 都进行前四步相同的操作

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
代码:

void quick_sort(int a[], int l, int r)
{
	if(l >= r) // 递归结束条件 
		return;
	
	int t = a[l];
	int i = l, j = r;
	
	while(i < j)
	{
		while(i < j && a[j] >= t) // 右指针的移动 
			j--;
		
		while(i < j && a[i] <= t) // 左指针的移动 
			i++
			
		if(i < j)
		{
			int h = a[i];
			a[i] = a[j];
			a[j] = h;
		}
	}
	a[l] = a[i];
	a[i] = t;
						// 对分成的两部分继续进行排序	
	quick_sort(a, l, i);
	quick_sort(a, i + 1, r);
}

快速排序并不是所有情况都快:
① 最坏情况:序列接近有序,时间复杂度为 O(n * n)
② 最好情况:序列接近无序,时间复杂度为O(n logn)
③ 快速排序为不稳定排序

表排序

我们平常用的排序都是直接用于值交换(数字、字符等),但是在实际生活我们可不是仅仅只交换数字或者字符,一般都是一大部分内容的移动;直接进行值交换的话,时间的花费是相当恐怖的。

表排序:将 “指针” 进行排序(“指针” 并不是 C里的指针)。

我们继续用之前 直接插入排序的扑克牌举例:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
代码:

void table_sort(int card[], int table, int n) // card 下标从0开始 0 
{
	int i, j;
	int t;
	
	for(i = 0; i < n; i++)
		table[i] = i;
		
	for(i = 1; i < n; i++)
	{
		t = table[i];
		for(j = i; j > 0 && card[table[j - 1]] > card[t]; j--)
			table[j] = table[j - 1];
		
		table[j] = t;
	}
}

此处只是拿直接插入排序做例子
① 用到其他排序里也是同样的,但是要记得是换下标,时间复杂度与这些排序复杂度匹配
② 写的时候要细心,很容易出错

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值