排序算法
来源:互联网 发布:不可抗力网络剧百度云 编辑:程序博客网 时间:2024/06/02 03:57
本文对学习过的排序算法做简要的总结。如发现错误,欢迎纠正。
本文排序默认为升序。
1. 插入排序(冒泡排序)
插入排序也称为冒泡排序,学过C语言的应该都学习过。程序在下面。
冒泡排序使用了两个for循环:外循环for和内循环for。
原理如下:外循环for在第i次循环时,arr[0]至arr[i-1]已经排序完毕。第i次执行完以后,arr[0]至arr[i]排序完毕。也就是说,外循环for确认第i个元素的位置。
内循环for每次执行,都会判断当前的j-1元素是否比j元素大,如果大则交换这两个元素,直到j元素大于等于j-1元素。
#include <stdio.h>void swap(int *i, int *j){int temp;temp = *i;*i = *j;*j = temp;}void sort1(int arr[], int num){int i, j;for(i = 1; i < num; i++)for(j = i; j > 0 && arr[j-1]>arr[j]; j--)swap(&arr[j], &arr[j-1]);}void main(){ int x[10] = {51, 35, -3, 17, 24, -5, 11, 38, 90, 62};int i;sort1(x, 10);printf("After sort:\n");for(i = 0; i < 10; i++)printf("%d ", x[i]);printf("\n");}
输出结果:
After sort:
-5 -3 11 17 24 35 38 51 62 90
2. 改进的插入排序
冒泡排序时,每次都要交换相邻两个元素的值,这就要用到三个赋值语句。那么是否可以通过什么方法,减少赋值语句。
可以看出,交换相邻两个元素的值只不过是为了让第i个元素插入到正确的位置,那么我们可以考虑在执行内循环for之前,将第i个元素先取出来,然后来查找第i个
元素应该插入的位置,最后将第i个元素插入该位置即可。
程序如下。当内循环for执行完时,j也就是我们需要插入的位置。
#include <stdio.h>void sort2(int arr[], int num){int i, j, tmp;for(i = 1; i < num ; i++){tmp = arr[i];for(j = i; j > 0 && arr[j-1]> tmp; j--)arr[j] = arr[j-1];arr[j] = tmp; /*插入*/}}void main(){int i;int x[10] = {87, 56, 12, 65, -6, 63, 1, 98, 23, 85};sort2(x, 10);printf("After sort:\n");for(i = 0; i < 10; i++)printf("%d ", x[i]);printf("\n");}输出结果:
After sort:
-6 1 12 23 56 63 65 85 87 98
3. 快速排序1
这一节将介绍最简单的快速排序。该排序算法每次以待排序数组中的第一个元素为中值,将所以小于该值的元素放在数组左边,大于该元素放在数组的右边,最后将中值插入正确的位置。然后将中值左侧的子数组作为待排序数组重新调用该算法,同时也将中值右侧的子数组作为待排序数组重新调用该算法,直到最后只有一个或没有元素待排序。如此下去。可见,该算法使用了递归。
算法如下。
代码16~17为基准条件,当只有一个或没有元素待排序时,递归终止。
代码20-24完成了对左右两个子数组的划分,在执行第i次for循环时,m始终指向小于中值的最后一个元素,也就是说arr[lower+1...m] < 中值,且arr[m+1 ...i-1] >= 中值。
代码24将中指插入了正确的位置。
代码26和27则递归调用算法对左子数组和右子数组进行排序。
#include <stdio.h>swap(int *a, int*b){int temp;temp = *b;*b = *a;*a = temp;}void qsort1(int arr[], int lower, int upper){int i, m;if(lower >= upper)return; m = lower;for(i = lower+1; i <= upper; i++){if(arr[i] < arr[lower])swap(&arr[++m], &arr[i]);}swap(&arr[m], &arr[lower]);qsort1(arr, lower, m-1);qsort1(arr, m+1, upper);}void main(){int x[10] = {4, 54, 23, 12, 87, 85, 63, 31, 65, 43};int i;qsort1(x, 0, 9);for(i = 0; i < 10; i++)printf("%d ", x[i]);printf("\n");}
结果如下:
4 12 23 31 43 54 63 65 85 87
4. 快速排序2
现在假设对n个相同元素组成的数组进行排序。对于这种排序,插入排序的运行时间为O(n),因为每个元素的移动距离都为0。
而快速排序的性能非常差,N-1次划分中每次划分都需要O(n)时间来去掉一个元素,所以总的运行时间为O(n)。因此对快速排序1进行修改,使用双向划分来解决该问题。
算法如下面所示。
代码16~17为基准条件,当只有一个或没有元素带排序时,递归终止。
代码23为最外层while循环,该循环终止时表示排序已经完成。
代码24~25从左往右遍历数组,直到发现大于中值t的元素,因此该do...while退出时,i指向大于中值的元素。
代码26~27从右往左遍历数组,直到发现小于中值t的元素,因此该do...while退出时,j指向小于于中值的元素。
代码29到30判断是否该次排序是否结束。
代码31交换两个元素。交换以后,i指向小于中指的元素,而j指向小于中指的元素。
代码33当最外面的while(1)退出时,从左往右看,j指向最后一个小于中值的元素,因此对该元素和中指进行交换。
代码26和27则递归调用算法对左子数组和右子数组进行排序。
#include <stdio.h>void swap(int *a, int*b){int tmp;tmp = *b;*b = *a;*a = tmp;}void qsort3(int arr[], int lower, int upper){int t, i, j;if(lower >= upper)return;t = arr[lower];i = lower;j = upper+1;while(1){do i++;while(i <= upper && arr[i] < t);do j--;while(arr[j] > t);if(i > j)break;swap(&arr[i],&arr[j] );}swap(&arr[lower],&arr[j] );qsort3(arr, lower, j-1);qsort3(arr, j+1, upper);}void main(){int x[10] = {55, 41, 59, 26, 26, 26, 53, 58, 97, 93};int i;printf("Before qsort:\n");for(i = 0; i < 10; i++)printf("%d ", x[i]);printf("\n");qsort3(x, 0, 9);printf("After qsort:\n");for(i = 0; i < 10; i++)printf("%d ", x[i]);printf("\n");}
结果如下:
Before qsort:
55 41 59 26 26 26 53 58 97 93
After qsort:
26 26 26 41 53 55 58 59 93 97
2012.08.05添加算法1,2。
2012.08.08添加算法3。
2012.08.14添加算法4。
- 排序算法
- 排序算法
- 排序算法
- 排序算法
- 排序算法
- 排序算法
- 排序算法
- 排序算法
- 排序算法
- 排序算法
- 排序算法
- 排序算法
- 排序算法
- 排序算法
- 排序算法
- 排序算法
- 排序算法
- 排序算法
- Gson简要使用笔记
- [C/C++再探讨STL里的function和bind的实现
- C++中如何使类不能继承
- PHP include_path 分析
- 97 Things Every Software Architect Should Know
- 排序算法
- mac开发入门
- 转载:Posix多线程编程学习笔记
- 《python编程入门经典》学习笔记–第八章(一)
- JQuery动态操作表格(添加、删除、多选、全选删除行操作)
- AndEngine编译
- 感《明朝后期的中缅战争》
- 练习题
- Chapter09-"内核模式下的线程同步"之等待函数