1、什么是排序
排序就是将一串数据按照大小顺序重新排列
2、为什么需要排序
数据处理中经常用到的一种算法。
3、为什么有这么多的排序算法
一种新算法的提出,必定是为了解决某种算法在某方面的不足。以下表格简要介绍了几种排序算法的性能。
4、几种排序算法详解
本次代码测试使用C语音编写,其他语言亦可。
1、冒泡排序
冒泡排序顾名思义就是向吐泡泡一样,一次将一个最大数或者最小数排到数组的末尾,一次遍历下来就会找出一个最大/最小的数,然后接着遍历。如下动图很好的解释了这一排序算法。
分析得知:
1、比较两个数据,如果右边的比左边大,则交换两个数据的位置。
2、一遍遍历下来,最大的数据就在数组的末尾,我们需要考虑使用双重for循环实现。
3、重复1、2步骤,直到遍历完整个数组。
C语音实现如下:
//冒泡排序
void bubble_Sort(int *array, int n)
{
int i = 0;
int j = 0;
int temp = 0;
for(i = 0; i < n; i++)
{
for(j = 1; j < n - i; j++) //最大的数已经放到数组的末尾了,所以不需要再比较了 因此 j < n-i
{
if(array[j - 1] > array[j]) //如果右边比左边大,就交换数据
{
temp = array[j-1];
array[j - 1] = array[j];
array[j] = temp;
}
}
}
}
我们实际测试一下:
int main()
{
int i, num;
int array[] = {333,3,276,6,9,18,25,11,21,144,488,908,325,1,10,25,9,18,39,11,98,45};
num = sizeof(array)/sizeof(array[0]); //取数组长度
printf("sizeof(array)/sizeof(array[0]) = %d \n", num);
printf("原始数组是:\n");
for(i = 0 ; i < num ; i++)
{
printf("%d ", array[i]);
}
printf("\n");
bubble_Sort(array, num);
//quick_sort(array, num);
//insert_sort(array, num);
//select_sort(array, num);
printf("排序后的数组:\n");
for(i = 0 ; i < num ; i++)
{
printf("%d ", array[i]);
}
printf("\n");
return 0;
}
运行结果如下:
void@ubuntu:/mnt/hgfs/VMshare/code/c$ gcc sort.c
void@ubuntu:/mnt/hgfs/VMshare/code/c$ ./a.out
sizeof(array)/sizeof(array[0]) = 22
原始数组是:
333 3 276 6 9 18 25 11 21 144 488 908 325 1 10 25 9 18 39 11 98 45
排序后的数组:
1 3 6 9 9 10 11 11 18 18 21 25 25 39 45 98 144 276 325 333 488 908
void@ubuntu:/mnt/hgfs/VMshare/code/c$
2、选择排序
选择排序的思想是,我们先遍历一遍数组,找到最小的那个,放在数组第一个位置,然后我们接着遍历数组,找到第二小的数据,放在数组第二个位置,然后接着遍历数组,找到第三小的那个数据…同样放一个动图来理解一下选择排序的实现过程:
分析得知:
1、第一次遍历数组,找到最小的那个,和数组[0]交换。
2、第二次遍历数组,找到次小的那个,和数组[1]交换,一次类推。
3、同样可以使用双重for循环实现。
实现代码如下:
//选择排序
void select_sort(int array[], int n)
{
int i, j, k , temp;
for (i = 0; i< n; i++)
{
k = i ;
for(j = i+1 ; j < n; j ++)
{
if(array[j] < array[k]) //array[k] 一直记录最小的那个数
{
k = j;
}
}
if (k != i) //如果最小的那个数不是自己,则交换两个数的位置
{
temp = array[i];
array[i] = array[k];
array[k] = temp;
}
}
}
实际测试代码和结果同冒泡排序,不再赘述。
3、插入排序
插入排序的思想是,先将最开头的一个数据看成是有序的(因为只有一个数据,肯定是有序的嘛),然后依次查找后面的元素,按照顺序插入前面的有序表中。我们同样用一个动图来表示一下:
分析得知:
1、先将第一个数据看成是有序的。
2、依次遍历后续的数据,插入前面的有序表中。
3、后面的数据遍历完成后,一个有序表就完成了。
我们用代码分析一下:
//插入排序
void insert_sort(int array[], int n)
{
int i,j,temp;
for (i = 1; i < n; i++) //刚开始array[0]看做是一个有序表。
{
temp = array[i];
//将后面数据依次插入前面的有序表。从有序表的末尾开始查找,因为我们取出来一个数据,末尾刚好空出来了。
for (j = i - 1; j >= 0 && array[j] > temp; j--)
{
array[j+1] = array[j];
}
//有些同学可能理解不了,array[j+1] = array[j]; 后面为啥还有一个:array[j+1] = temp;
//其实 我们for循环中有个j--,所以这里又j+1 两个含义是不同的,要仔细体会一下
array[j+1] = temp;
}
}
测试代码同上,不在赘述。
4、快速排序
快速排序算法是1962年提出的,至今已经过去半个多世纪了,任然敢称为快速排序算法,可见这个算法是很叼的。所以需要我们认真学习。
快速排序算法的思想是:我们先找一个基数,然后按照这个基数把比它小的放在他的左边,比它大的放在它的右边,遍历一次后,基数在数组的中间,左边是比他小的数,右边是比他大的数。然后在分开的两个数组中再用此方法继续分类,最后数据就按顺序排好了。是不是很神奇,也有点不好理解,没关系,我们先放一个动图来理解一下:
我认为百度百科的解释简洁明了,直接套用。
实现的代码如下:
//快速排序
void sort_swap(int *array, int left, int right)
{
int temp;
temp = array[left];
array[left] = array[right];
array[right] = temp;
}
//这个函数时快速排序算法实现的核心
unsigned int find_quick_sort_median(int *array, int left, int right)
{
int temp = array[left];
while (left < right)
{
while(left < right && temp <= array[right])
{
right --;
}
sort_swap(array, left, right);
while(left < right && temp >= array[left])
{
left ++;
}
sort_swap(array, left, right);
}
return left;
}
void q_sort(int array[], int left, int right)
{
int temp = 0;
if(left < right)
{
//快速排序算法分而治之的思想
temp = find_quick_sort_median(array, left, right);
q_sort(array, 0, temp-1);
q_sort(array, temp+1, right);
}
}
void quick_sort(int *array, int n)
{
q_sort(array, 0, n-1);
}
运行结果同上,不再赘述。
5、总结
各种排序算法的实现各不相同,在一些简单的场合下,我们使用哪种排序算法都无伤大雅。但是处理的数据非常多的时候,就要考虑使用哪种算法更优了。快速排序算法经过这么多年的发展,依然敢叫快速排序算法,可见:这种算法的速度确实是最快的。但是快速排序算法也有缺点:使用递归,如果数据很多的话,会消耗大量的内存。
现在我们选择排序算法,不是单独选择某一个,比如对于大数据量的排序,我们先使用快速排序算法,将数据分成几拨,然后使用选择排序或者插入排序。这样就兼顾各个算法的优缺点,达到排序性能最优。
排序算法需要研究的内容太多,不是几个经典排序算法就能解决的。后续有时间、有精力,再详细研究一下各个算法的优化以及几个排序算法的组合。