排序算法
所谓排序,就是使一串记录,按照其中的某个或某些关键字的大小,递增或递减的排列起来的操作。排序算法,就是如何使得记录按照要求排列的方法。排序算法在很多领域得到相当地重视,尤其是在大量数据的处理方面。一个优秀的算法可以节省大量的资源。在各个领域中考虑到数据的各种限制和规范,要得到一个符合实际的优秀算法,得经过大量的推理和分析。
1. 冒泡排序
排序步骤
- 从数组的第一个数
arr[0]
开始遍历,(i从0到n-1)如果第i个数比第i+1个数大arr[i]>arr[i+1]
,则交换 - 重复上述步骤直至数组有序
分析
冒泡排序可以说是最简单的排序方法之一,最坏的情况需要排n-1趟。我们可以设置一个flag
来监测排序过程中是否产生的数的交换,如果没有,说明数组已经有序,则可以不用进行下一趟排序。
C语言实现
void bubble_sort(int arr[],int n)
{
int flag,tmp;
for(int i = 0; i < n-1; i++)
{
flag = 0;
for(int j = 0;j<n-1;j++)
if(arr[j]>arr[j+1])
{
tmp = arr[j];
arr[j] = arr[j+1];
arr[j+1] = tmp;
flag = 1;
}
if(!flag)
return;
}
}
2.快速排序算法
排序步骤
- 在当前区域(记为area)(area初始为整个无序数组)选定一个数作为基准数(记为key)
- 遍历数组,把所有大于key的数(记为high)放在右边,把所有小于key的数(记为low)放在左边(并不关心这些数是否有序)
- 把key放在low和high的中间
- 现在area又被分为三个区域,lowkeyhigh,分别选择low和high作为新的area,分别重复上述流程
原理分析
每次我们在当前area中把所有数以key为中间数摆放好,实质上就是在整个数组中确定好了key这个数最终的位置,左边的数都比key小,右边的数都比key大。不断重复这个过程那么最终所有数都必将摆在最终的位置
手动排序示例
下面是一个无序数组:
8 ,5, 2, 3,-1 , 7
当前area为[0] ~ [5] (数组编号)我们选择中间的一个数2作为本轮的key
从两端开始找:
7 比 key 大,没毛病
-1 比 key 小,扔到最左边,现在数组:
-1,5, 2, 3, 8 , 7
移动过的数和比过大小没移动的数都是已处理的数(我用粗体标记了),待在了自己该待在的区域,因此我们不需要对这些数再进行操作,也不应该用其他的数来填充他们的位置,因为我们不关心他们之间是否有序,只关心他们和key的位置关系是否正确
然后我们从左边开始找,(如果继续从右边找会重复工作,不信你可以动手试一下)
-1是刚刚丢过来的,不用管
5比key大,移动到未处理的最右边:
-1,3,2,5,8 ,7
我们并没有检查交换过来的数和key的关系,因此交换过来的数是未处理的数
继续,2等于key,移到左边:(等号的情况必须得移动,不然key的位置就被固定了!但比key小的数在key左边不一定放的下)
-1,2,3,5,8 ,7
最后3的位置是在2右边的,不需要动,第一趟完成,现在[0]是low,[2]~[5] 是high
因为low只有一个数,不需要继续处理
现在high是新的area:
3,5,8 ,7
为了展示key的选取不影响排序结果(虽然影响排序效率),我们选择第一个数3作为key
那么跑完整个流程,所有的数都大于等于3,这次就没有low区域了
选择新的high作为area:
5, 8, 7
这次又随机选,选最后一个数7(读者可以自行尝试选取其他的key进行排序)
7不动,8比key大
5, 7, 8
到这显而易见已经完成了
C语言实现
void quick_sort(int arr[],int l,int r)
{
if(l>=r) return;
int i=l,j=r,key=arr[l];
while(i<j)
{
while(i<j && arr[j]>=key) j--;
if(i<j) arr[i++]=arr[j];
while(i<j && arr[i]<=key) i++;
if(i<j) arr[j]=arr[i];
}
arr[i]=key;
quick_sort(arr,l,i-1);
quick_sort(arr,i+1,r);
}