常用排序的实现及比较
2017-07-30 19:01
190 查看
排序的稳定性:假设在待排序的序列中存在多个相同关键字的记录,经过排序,这些关键字的位置保持不变,则称这个排序算法是稳定的,否则是不稳定的。
1. 选择排序(不稳定)
选择排序是一种直观的排序算法,每次找到最大的或者最小的数与,存放在序列的起始元素,知道所有的元素都排序结束。选择排序是不稳定的,假设5,5,3进行排序,3比第一个5小交换位置,导致第一个5摞到第二个5后面,所以选择排序是不稳定的排序。
以下面5个无序的数据为例:
56 12 80 91 20
排序过程:
a.12 56 80 91 20
b.12 20 80 91 56
c.12 20 56 91 80
d.12 20 56 80 91
代码实现:
2.简单交换排序(稳定排序)
根据序列中两个关键字的比较结果来对换在序列中的位置,交换排序的特点是:将键值较大的记录向序列的尾部移动,键值较小的记录向序列的前部移动。
以下面5个无序的数据为例:
8 2 1 4 9 5 7 3 6
a.(只细讲第一趟)
2 8 1 4 9 5 7 3 6
1 2 8 4 9 5 7 3 6(1是序列中最小的)
3.冒泡排序(稳定排序)
冒泡排序是临近的数字两两进行比较,按照从小到大或者从大到小的顺序进行交换。
以下面的数字为例子:
6 2 4 1 5 9
a. 2 6 4 1 5 9
2 4 6 1 5 9
2 4 1 6 5 9
2 4 1 5 6 9
2 4 1 5 6 9
b. 2 1 4 5 6 9
c. 1 2 4 5 6 9
假设一组数后面的数是排好序的,则代码需要进行优化
4.插入排序(稳定排序)
有一个已经有序的数据序列,要求在这个已经排好的数据序列中插入一个数,但要求插入后此数据序列仍然有序,这个时候就要用到一种新的排序方法——插入排序法,插入排序的基本操作就是将一个数据插入到已经排好序的有序数据中,从而得到一个新的、个数加一的有序数据,算法适用于少量数据的排序。
以下列数字为例:
65 27 59 64 58
刚开始时把65认为已经排好序
a.插入27
27 65 59 64 58
b.插入59
27 59 65 64 58
c.插入64
27 59 64 65 58
d.插入58
27 58 59 64 65
5.希尔排序(不稳定排序)
希尔排序属于插入排序的一种,也称缩小增量排序,是直接插入排序算法的一种更高效的改进版本。把记录按步长 gap 分组,对每组记录采用直接插入排序方法进行排序。随着步长逐渐减小,所分成的组包含的记录越来越多,当步长的值减小到 1 时,整个数据合成为一组,构成一组有序记录,则完成排序。
排序前: 9 1 2 5 7 4 8 6 3 5
gap = 5: 4 1 2 3 5 9 8 6 5 7
gap = 2: 2 1 4 3 5 6 5 7 8 9
gap = 1: 1 2 3 4 5 5 6 7 8 9
排序后: 1 2 3 4 5 5 6 7 8 9
6.归并排序(稳定排序)
归并排序是建立在归并操作上的一种有效的排序算法。该算法是采用分治法(Divide and Conquer)的一个非常典型的应用。将待排序序列R[0…n-1]看成是n个长度为1的有序序列,将相邻的有序表成对归并,得到n/2个长度为2的有序表;将这些有序序列再次归并,得到n/4个长度为4的有序序列;如此反复进行下去,最后得到一个长度为n的有序序列。
7.堆排序
堆排序(Heapsort)是指利用堆积树(堆)这种数据结构所设计的一种排序算法,它是选择排序的一种。可以利用数组的特点快速定位指定索引的元素。
8.快速排序
快速排序由C. A. R. Hoare在1962年提出。它的基本思想是:通过一趟排序将要排序的数据分割成独立的两部分,其中一部分的所有数据都比另外一部分的所有数据都要小,然后再按此方法对这两部分数据分别进行快速排序,整个排序过程可以递归进行,以此达到整个数据变成有序序列。
对这8种常用排序的时间复杂度和空间复杂度分析
1. 选择排序(不稳定)
选择排序是一种直观的排序算法,每次找到最大的或者最小的数与,存放在序列的起始元素,知道所有的元素都排序结束。选择排序是不稳定的,假设5,5,3进行排序,3比第一个5小交换位置,导致第一个5摞到第二个5后面,所以选择排序是不稳定的排序。
以下面5个无序的数据为例:
56 12 80 91 20
排序过程:
a.12 56 80 91 20
b.12 20 80 91 56
c.12 20 56 91 80
d.12 20 56 80 91
代码实现:
void select_sort(int *arr,int len) { if( arr == NULL || len < 0) { return ; } int i = 0; for( i = 0;i < len - 1;i++) { int min = arr[i]; int min_index = i; for( int j = i + 1;j < len;j++) { if( arr[j] < min) { min = arr[j]; min_index = j; } } swap(&arr[i],&arr[min_index]); } }
2.简单交换排序(稳定排序)
根据序列中两个关键字的比较结果来对换在序列中的位置,交换排序的特点是:将键值较大的记录向序列的尾部移动,键值较小的记录向序列的前部移动。
以下面5个无序的数据为例:
8 2 1 4 9 5 7 3 6
a.(只细讲第一趟)
2 8 1 4 9 5 7 3 6
1 2 8 4 9 5 7 3 6(1是序列中最小的)
void exchange_sort(int *arr,int len) { if( arr == NULL || len < 0) { return ; } int i = 0; for( i = 0; i < len - 1;i++) { for( int j = i + 1;j < len ;j++) { if( arr[i] > arr[j]) { swap(&arr[j],&arr[i]); } } } }
3.冒泡排序(稳定排序)
冒泡排序是临近的数字两两进行比较,按照从小到大或者从大到小的顺序进行交换。
以下面的数字为例子:
6 2 4 1 5 9
a. 2 6 4 1 5 9
2 4 6 1 5 9
2 4 1 6 5 9
2 4 1 5 6 9
2 4 1 5 6 9
b. 2 1 4 5 6 9
c. 1 2 4 5 6 9
void bubble_sort(int *arr,int len) { if( arr == NULL || len < 0) { return ; } for( int i = 0;i < len - 1;i++) { for( int j = 0;j < len - 1 - i;j++) { if( arr[j] > arr[j+1]) { swap(&arr[j],&arr[j+1]); } } } }
假设一组数后面的数是排好序的,则代码需要进行优化
bool bubble_sort_ex(int *arr,int len) { if( arr == NULL || len < 0) { return false; } for( int i = 0;i < len - 1;i++) { bool flag = true; for( int j = 0;j < len - 1 - i;j++) { if( arr[j] > arr[j+1]) { swap(&arr[j],&arr[j+1]); flag = false; } } if( flag ) { break; } } return false; }
4.插入排序(稳定排序)
有一个已经有序的数据序列,要求在这个已经排好的数据序列中插入一个数,但要求插入后此数据序列仍然有序,这个时候就要用到一种新的排序方法——插入排序法,插入排序的基本操作就是将一个数据插入到已经排好序的有序数据中,从而得到一个新的、个数加一的有序数据,算法适用于少量数据的排序。
以下列数字为例:
65 27 59 64 58
刚开始时把65认为已经排好序
a.插入27
27 65 59 64 58
b.插入59
27 59 65 64 58
c.插入64
27 59 64 65 58
d.插入58
27 58 59 64 65
void insert_sort(int *arr,int len) { if( arr == NULL || len < 0) { return ; } int i = 0; int j = 0; for(i = 1;i < len;i++) { int temp = arr[i]; for( j = i - 1; j >= 0;j--) { if( arr[j] > temp) { arr[j+1] = arr[j]; } else { break; } } arr[j+1] = temp; } }
5.希尔排序(不稳定排序)
希尔排序属于插入排序的一种,也称缩小增量排序,是直接插入排序算法的一种更高效的改进版本。把记录按步长 gap 分组,对每组记录采用直接插入排序方法进行排序。随着步长逐渐减小,所分成的组包含的记录越来越多,当步长的值减小到 1 时,整个数据合成为一组,构成一组有序记录,则完成排序。
排序前: 9 1 2 5 7 4 8 6 3 5
gap = 5: 4 1 2 3 5 9 8 6 5 7
gap = 2: 2 1 4 3 5 6 5 7 8 9
gap = 1: 1 2 3 4 5 5 6 7 8 9
排序后: 1 2 3 4 5 5 6 7 8 9
void shell(int *arr,int len, int gap) { int i; int j; // // 把距离为 gap 的元素编为一个组,扫描所有组 for (i =gap; i<len; i++) { int tmp = arr[i]; for (j=i-gap; j>=0 && arr[j] > tmp; j -= gap) //// 对距离为 gap 的元素组进行排序 { arr[j+gap] = arr[j]; } arr[j+gap] = tmp; } } void shell_sort(int *arr,int len) { for (int i=len/1000 ;i>1; i=i/2) //计算gap { shell(arr, len ,i); } shell(arr, len ,1); }
6.归并排序(稳定排序)
归并排序是建立在归并操作上的一种有效的排序算法。该算法是采用分治法(Divide and Conquer)的一个非常典型的应用。将待排序序列R[0…n-1]看成是n个长度为1的有序序列,将相邻的有序表成对归并,得到n/2个长度为2的有序表;将这些有序序列再次归并,得到n/4个长度为4的有序序列;如此反复进行下去,最后得到一个长度为n的有序序列。
static int tmp[20] = {0} // 把两个有序的数组排序成一个数组 void merge(int *arr, int start, int middle, int end) { int first = start; int second = middle + 1; int index = start; while ((first <= middle) && (second <= end)){ if (arr[first] >= arr[second]) tmp[index++] = arr[second++]; else tmp[index++] = arr[first++]; } while(first <= middle) tmp[index++] = arr[first++]; while(second <= end) tmp[index++] = arr[second++]; for (first = start; first <= end; first++) { arr[first] = tmp[first]; } } // 递归划分数组 void merge_Sort(int *array, int start, int end) { if (start >= end) return; int middle = ((end + start) >> 1); merge_Sort(array, start, middle);// 递归划分左边的数组 merge_Sort(array, middle+1, end);// 递归划分右边的数组 merge(array, start, middle, end);// 对有序的两个数组进行合并成一个有序的数组 }
7.堆排序
堆排序(Heapsort)是指利用堆积树(堆)这种数据结构所设计的一种排序算法,它是选择排序的一种。可以利用数组的特点快速定位指定索引的元素。
void heap_adjust(int *arr, int start, int end) { int i; int tmp = arr[start]; for (i=2*start+1; i<=end; i=2*i+1) { if (i+1<=end && arr[i] < arr[i+1]) { i++; } if (tmp < arr[i]) { arr[start] = arr[i]; start = i; } else { break; } } arr[start] = tmp; } char *heap_sort(int *arr, int len) //3/2N * Log2N { //1.从下到上,建立大根堆 for (int i=(len-2)/2; i>=0; i--)//N/2*log2N { heap_adjust(arr,i,len-1); } //2.交换 swap(&arr[0], &arr[len-1]); //3.调整为大根堆 for (int i=len-2; i>0 ;i--) //N*log2N { heap_adjust(arr,0,i); swap(&arr[0], &arr[i]); } return __FUNCTION__; }
8.快速排序
快速排序由C. A. R. Hoare在1962年提出。它的基本思想是:通过一趟排序将要排序的数据分割成独立的两部分,其中一部分的所有数据都比另外一部分的所有数据都要小,然后再按此方法对这两部分数据分别进行快速排序,整个排序过程可以递归进行,以此达到整个数据变成有序序列。
void partition(int *arr,int L, int R) { if (L >= R) { return ; } int left = L; int right = R; int tmp = arr[L]; while(L<R) { while(tmp <= arr[R] && L<R) { R--; } arr[L] = arr[R]; while(arr[L] <= tmp && L<R) { L++; } arr[R] = arr[L]; } arr[L] = tmp; partition(arr,left,L-1); partition(arr,L+1,right); } void quick_sort(int *arr, int len) { partition(arr, 0, len-1); }
对这8种常用排序的时间复杂度和空间复杂度分析
相关文章推荐
- 主流数据库之间对SQL:2003标准的不同实现方法比较(第二部分 结果集排序)
- java实现常用的八种内排序方法
- java 数组比较,元素的比较,Comparable,Comparator比较的应用实现,排序,查找示例
- 常用排序的java实现
- 常用算法Java实现之选择排序
- 对象的比较与排序(三):实现IComparable<T>和IComparer<T>泛型接口
- 数组排序方法的性能比较(中):Array.Sort 实现分析
- Java实现8中常用的排序
- 微软笔试题 大型文件外部排序(二路归并和k路归并的实现和比较)
- 用JAVA实现一种排序,JAVA类实现序列化的方法(二种)? 如在COLLECTION框架中,实现比较要实现什么样的接
- 常用排序的实现方法(数据结构)
- 主流数据库之间对SQL:2003标准的不同实现方法比较(第二部分 结果集排序)
- 九种常见排序的比较和实现
- 一起谈.NET技术,数组排序方法的性能比较(3):LINQ排序实现分析
- java中各种常用排序实现(直接插入排序、直接选择排序、堆排序、冒泡排序、快速排序和归并排序)
- 常用数组排序方法(Java实现)
- 排序(各种排序方法的实现与比较)
- golang实现常用排序算法 --- 快速排序、堆排序等
- 比较和排序(IComparable和IComparer以及它们的泛型实现)
- Java编程之TreeSet排序两种解决方法(1)元素自身具备比较功能,元素需要实现Comparable接口覆盖compare(2)创建根据自定义Person类的name进行排序的Comparator