@yanglt7
2018-10-21T15:48:11.000000Z
字数 10833
阅读 754
数据结构和算法
概念
在排序问题中,通常将数据元素称为记录。
排序的依据是关键字之间的大小关系,那么对同一记录集合,针对不同的关键字进行排序,可以得到不同的序列。
分类
插入排序类
选择排序类
交换排序类
归并排序类
冒泡排序的要点
代码实现
#include <stdio.h>void BubbleSort(int k[], int n){int i, j, temp, count1=0, count2=0;for( i=0; i < n-1; i++ ){for( j=i+1; j < n; j++ ){count1++;if( k[i] > k[j] ){count2++;temp = k[j];k[j] = k[i];k[i] = temp;}}}printf("总共进行了%d次比较,进行了%d次移动!\n", count1, count2);}int main(){int i;int a[10] = {5, 2, 6, 0, 3, 9, 1, 7, 4, 8};BubbleSort(a, 10);printf("排序后的结果是: \n");for( i=0; i < 10; i++ ){printf("%d", a[i]);}printf("\n");return 0;}
#include <stdio.h>void BubbleSort(int k[], int n){int i, j, temp, count1=0, count2=0;int flag = 1;for( i=0; i < n-1 && flag; i++ ){for( j=n-1; j > i; j-- ){count1++;flag = 0;if( k[j-1] > k[j] ){count2++;temp = k[j-1];k[j-1] = k[j];k[j] = temp;flag = 1;}}}printf("总共进行了%d次比较,进行了%d次移动!\n", count1, count2);}int main(){int i;int a[10] = {5, 2, 6, 0, 3, 9, 1, 7, 4, 8};BubbleSort(a, 10);printf("排序后的结果是: \n");for( i=0; i < 10; i++ ){printf("%d", a[i]);}printf("\n");return 0;}
选择排序算法就是通过n-i次关键字间的比较,从n-i+1个记录中最小的记录,并和第i(1<=i<=n)个记录交换。
代码实现
#include <stdio.h>void SelectSort(int k[], int n){int i, j, min, temp, count1=0, count2=0;for( i=0; i < n-1; i++ ){min = i;for( j=i+1; j < n; j++ ){count1++;if( k[j] < k[min] ){min = j;}}if( min != i ){count2++;temp = k[min];k[min] = k[i];k[i] = temp;}}printf("总共进行了%d次比较,进行了%d次移动!\n", count1, count2);}int main(){int i;int a[10] = {5, 2, 6, 0, 3, 9, 1, 7, 4, 8};SelectSort(a, 10);printf("排序后的结果是: \n");for( i=0; i < 10; i++ ){printf("%d", a[i]);}printf("\n");return 0;}
直接插入排序算法(Straight Insertion Sort)的基本操作是将一个记录插入到已经排好序的有序表中,从而得到一个新的、记录数增加1的有序表。
代码实现
#include <stdio.h>void InsertSort(int k[], int n){int i, j, temp;for( i=1; i < n; i++ ){if( k[i] < k[i-1] ){temp = k[i];for( j=i-1; k[j] > temp; j-- ){k[j+1] = k[j];}k[j+1] = temp;}}}int main(){int i;int a[10] = {5, 2, 6, 0, 3, 9, 1, 7, 4, 8};InsertSort(a, 10);printf("排序后的结果是: \n");for( i=0; i < 10; i++ ){printf("%d", a[i]);}printf("\n");return 0;}
| 初始关键字 | 49 | 38 | 65 | 97 | 76 | 13 | 27 | 49 | 55 | 04 |
|---|---|---|---|---|---|---|---|---|---|---|
| 一趟排序结果 | 13 | 27 | 49 | 55 | 04 | 49 | 38 | 65 | 97 | 76 |
| 二趟排序结果 | 13 | 04 | 49 | 38 | 27 | 49 | 55 | 65 | 97 | 76 |
| 三趟排序结果 | 04 | 13 | 27 | 38 | 49 | 49 | 55 | 65 | 76 | 97 |
#include <stdio.h>void ShellSort(int k[], int n){int i, j, temp;int gap = n;do{gap /= 3;for( i=gap; i < n; i++ ){if( k[i] < k[i-gap] ){temp = k[i];for( j=i-gap; k[j] > temp; j-=gap ){k[j+gap] = k[j];}k[j+gap] = temp;}}} while(gap > 0);}int main(){int i;int a[10] = {5, 2, 6, 0, 3, 9, 1, 7, 4, 8};ShellSort(a, 10);printf("排序后的结果是: \n");for( i=0; i < 10; i++ ){printf("%d", a[i]);}printf("\n");return 0;}
堆,是具有以下性质的完全二叉树
要点
根结点一定是堆中所有结点最大或者最小者,如果按照层序遍历的方式给结点从1开始编号,则结点之间满足如下关系:
下标i与2i和2i+1是双亲和子女关系
堆排序(Heap Sort)就是利用堆进行排序的算法,它的基本思想是:
代码实现
#include <stdio.h>int count = 0;void swap(int k[], int i, int j){int temp;temp = k[i];k[i] = k[j];k[j] = temp;}void HeapAdjust(int k[], int s, int n){int i, temp;temp = k[s];// i=2*s:左孩子; 2*s+1: 右孩子for( i=2*s; i <= n; i*=2 ){count++;if( i < n && k[i] < k[i+1] ) // 左孩子小于右孩子{i++; // 使得i指向最大的孩子的下标}if( temp >= k[i] ) // temp临时存放当前需要调整的双亲。如果大于孩子,则退出循环{break;}k[s] = k[i];s = i;}k[s] = temp;}void HeapSort(int k[], int n){int i;// 从下至上,从右至左,层序遍历for( i=n/2; i > 0; i-- ){HeapAdjust(k, i, n); // 构建大顶堆的函数。 k:数组 i:当前双亲结点; n:长度}for( i=n; i > 1; i-- ){swap(k, 1, i); // 调整,将第一个元素和最后一个元素进行互换,i是变化的HeapAdjust(k, 1, i-1); // 重新调整}}int main(){int i;int a[10] = {-1, 5, 2, 6, 0, 3, 9, 1, 7, 4};HeapSort(a, 9);printf("总共执行 %d 次比较! \n", count);printf("排序后的结果是: ");for( i=1; i < 10; i++ ){printf("%d ", a[i]);}printf("\n");return 0;}
归并排序(Merge Sort)就是利用归并的思想实现的排序方法。它的原理是假设初始有n个记录,则可以看成是n个有序的子序列,每个子序列的长度为1,然后两两归并,得到[n/2]个长度为2或1的有序子序列;然后再两两归并,……,如此重复,直至得到一个长度为n的有序序列为止,这种排序方法称为2路归并排序。
归并排序的递归实现
// 递归实现#include <stdio.h>#define MAXSIZE 10//实现归并,并把最后的结果存放到list1数组void merging(int *list1, int list1_size, int *list2, int list2_size){int i, j, k, m;int temp[MAXSIZE];i = j = k = 0while( i < list1_size && j < list2_size ){if( list1[i] < list2[j] ){temp[k++] = list1[i++];}else{temp[k++] = list2[j++];}}while( i < list1_size ){temp[k++] = list1[i++];}while( j < list2_size ){temp[k++] = list2[j++];}for( m=0; m < (list1_size + list2_size); m++ ){list1[m] = temp[m];}}void MergeSort(int k[], int n){if( n > 1 ){int *list1 = k;int list1_size = n/2;int *list2 = k + n/2; // 左半部分的地址加上左半部分的尺寸int list2_size = n - list1_size;MergeSort(list1, list1_size);MergeSort(list2, list2_size);merging(list1, list1_size, list2, list2_size);}}int main(){int i;int a[10] = {5, 2, 6, 0, 3, 9, 1, 7, 4, 8};MergeSort(a, 10);printf("排序后的结果是: \n");for( i=0; i < 10; i++ ){printf("%d", a[i]);}printf("\n");return 0;}
// 迭代实现#include <stdio.h>#include <stdlib.h>#define MAXSIZE 10void MergeSort(int k[], int n){int i, next, left_min, left_max, right_min, right_max;// 申请空间存放数组int *temp = (int *)malloc(n * sizeof(int));// 逐级递增比较for( i=1; i < n; i*=2 ) // 步长i{for( left_min=0; left_min < n-i; left_min = right_max ){right_min = left_max = left_min + i;right_max = left_max + i;// 右边的下标最大值只能为n,防止越界if( right_max > n ){right_max = n;}// temp数组的下标,由于每次数据都有返回到k,因此每次都需重新置零next = 0;// 如果左边的数据还没有到分割线且右边的数据也没有到分割线,则循环while( left_min < left_max && right_min < right_max ){if( k[left_min] < k[right_min] ){temp[next++] = k[left_min++]; // 存放较小者}else{temp[next++] = k[right_min++];}}// 如果左边的游标没有到达分割线,则需要把数组接回去// 如果右边的游标没有到达分割线,则说明右边的数据比较大,不需要移动位置while( left_min < left_max ){k[--right_min] = k[--left_max];}while( next > 0 ){// 将排好序的数组返回给kk[--right_min] = temp[--next];}}}}int main(){int i;int a[10] = {5, 2, 6, 0, 3, 9, 1, 7, 4, 8};MergeSort(a, 10);printf("排序后的结果是: \n");for( i=0; i < 10; i++ ){printf("%d", a[i]);}printf("\n");return 0;}
#include <stdio.h>void swap(int k[], int low, int high){int temp;temp = k[low];k[low] = k[high];k[high] = temp;}int Partition(int k[], int low, int high){int point;point = k[low];while( low < high ){while( low < high && k[high] >= point ){high--;}swap(k, low, high);while( low < high && k[low] <= point ){low++;}swap(k, low, high);}return low;}void QSort(int k[], int low, int high){int point;if( low < high ){point = Partition(k, low, high); // 计算基准点,将小于基准点的数放在左边,大的放在右边QSort(k, low, point-1);QSort(k, point+1, high);}}void QuickSort(int k[], int n){QSort(k, 0, n-1);}int main(){int i;int a[10] = {5, 2, 6, 0, 3, 9, 1, 7, 4, 8};QuickSort(a, 10);printf("排序后的结果是: \n");for( i=0; i < 10; i++ ){printf("%d", a[i]);}printf("\n");return 0;}
#include <stdio.h>void swap(int k[], int low, int high){int temp;temp = k[low];k[low] = k[high];k[high] = temp;}int Partition(int k[], int low, int high){int point;int m = low + (high-low)/2;if( k[low] > k[high] ){swap(k, low, high);}if( k[m] > k[high] ){swap(k, m, high);}if( k[m] > k[low] ){swap(k, m, low);}// 将low变成中间值point = k[low];while( low < high ){while( low < high && k[high] >= point ){high--;}swap(k, low, high);while( low < high && k[low] <= point ){low++;}swap(k, low, high);}}void QSort(int k[], int low, int high){int point;if( low < high ){point = Partition(k, low, high); // 计算基准点,将小于基准点的数放在左边,大的放在右边QSort(k, low, point-1);QSort(k, point+1, high);}}void QuickSort(int k[], int n){QSort(k, 0, n-1);}int main(){int i;int a[10] = {5, 2, 6, 0, 3, 9, 1, 7, 4, 8};QuickSort(a, 10);printf("排序后的结果是: \n");for( i=0; i < 10; i++ ){printf("%d", a[i]);}printf("\n");return 0;}
#include <stdio.h>void swap(int k[], int low, int high){int temp;temp = k[low];k[low] = k[high];k[high] = temp;}int Partition(int k[], int low, int high){int point;int m = low + (high-low)/2;if( k[low] > k[high] ){swap(k, low, high);}if( k[m] > k[high] ){swap(k, m, high);}if( k[m] > k[low] ){swap(k, m, low);}// 将low变成中间值point = k[low];while( low < high ){while( low < high && k[high] >= point ){high--;}k[low] = k[high];while( low < high && k[low] <= point ){low++;}k[high] = k[low];}k[low] = point;}void QSort(int k[], int low, int high){int point;if( low < high ){point = Partition(k, low, high); // 计算基准点,将小于基准点的数放在左边,大的放在右边QSort(k, low, point-1);QSort(k, point+1, high);}}void QuickSort(int k[], int n){QSort(k, 0, n-1);}int main(){int i;int a[10] = {5, 2, 6, 0, 3, 9, 1, 7, 4, 8};QuickSort(a, 10);printf("排序后的结果是: \n");for( i=0; i < 10; i++ ){printf("%d", a[i]);}printf("\n");return 0;}
#include <stdio.h>#define MAX_LENGTH_INSERT_SORT 7void ISort(int k[], int n){int i, j, temp;for( i=1; i < n; i++ ){if( k[i] < k[i-1] ){temp = k[i];for( j=i-1; k[j] > temp; j-- ){k[j+1] = k[j];}k[j+1] = temp;}}}void InsertSort(int k[], int low, int high){ISort(k+low, high-low+1);}void swap(int k[], int low, int high){int temp;temp = k[low];k[low] = k[high];k[high] = temp;}int Partition(int k[], int low, int high){int point;int m = low + (high-low)/2;if( k[low] > k[high] ){swap(k, low, high);}if( k[m] > k[high] ){swap(k, m, high);}if( k[m] > k[low] ){swap(k, m, low);}// 将low变成中间值point = k[low];while( low < high ){while( low < high && k[high] >= point ){high--;}k[low] = k[high];while( low < high && k[low] <= point ){low++;}k[high] = k[low];}k[low] = point;}void QSort(int k[], int low, int high){int point;if( high - low > MAX_LENGTH_INSERT_SORT ){point = Partition(k, low, high); // 计算基准点,将小于基准点的数放在左边,大的放在右边QSort(k, low, point-1);QSort(k, point+1, high);}else{InsertSort(k, low, high);}}void QuickSort(int k[], int n){QSort(k, 0, n-1);}int main(){int i;int a[10] = {5, 2, 6, 0, 3, 9, 1, 7, 4, 8};QuickSort(a, 10);printf("排序后的结果是: \n");for( i=0; i < 10; i++ ){printf("%d", a[i]);}printf("\n");return 0;}
#include <stdio.h>#define MAX_LENGTH_INSERT_SORT 7void ISort(int k[], int n){int i, j, temp;for( i=1; i < n; i++ ){if( k[i] < k[i-1] ){temp = k[i];for( j=i-1; k[j] > temp; j-- ){k[j+1] = k[j];}k[j+1] = temp;}}}void InsertSort(int k[], int low, int high){ISort(k+low, high-low+1);}void swap(int k[], int low, int high){int temp;temp = k[low];k[low] = k[high];k[high] = temp;}int Partition(int k[], int low, int high){int point;int m = low + (high-low)/2;if( k[low] > k[high] ){swap(k, low, high);}if( k[m] > k[high] ){swap(k, m, high);}if( k[m] > k[low] ){swap(k, m, low);}// 将low变成中间值point = k[low];while( low < high ){while( low < high && k[high] >= point ){high--;}k[low] = k[high];while( low < high && k[low] <= point ){low++;}k[high] = k[low];}k[low] = point;}void QSort(int k[], int low, int high){int point;if( high - low > MAX_LENGTH_INSERT_SORT ){while( low < high ){point = Partition(k, low, high); // 计算基准点,将小于基准点的数放在左边,大的放在右边if( point-low < high-point ){QSort(k, low, point-1);low = point + 1;}else{QSort(k, point+1, high);high = point-1;}}}else{InsertSort(k, low, high);}}void QuickSort(int k[], int n){QSort(k, 0, n-1);}int main(){int i;int a[10] = {5, 2, 6, 0, 3, 9, 1, 7, 4, 8};QuickSort(a, 10);printf("排序后的结果是: \n");for( i=0; i < 10; i++ ){printf("%d", a[i]);}printf("\n");return 0;}
| 排序方法 | 平均情况 | 最好情况 | 最坏情况 | 辅助空间 | 稳定性 |
|---|---|---|---|---|---|
| 冒泡排序 | O(n^2) | O(n) | O(n^2) | O(1) | 稳定 |
| 选择排序 | O(n^2) | O(n^2) | O(n^2) | O(1) | 稳定 |
| 直接插入排序 | O(n^2) | O(n) | O(n^2) | O(1) | 稳定 |
| 希尔排序 | O(nlogn)~O(n^2) | O(n^1.3) | O(n^2) | O(1) | 不稳定 |
| 堆排序 | O(nlogn) | O(nlogn) | O(nlogn) | O(1) | 不稳定 |
| 归并排序 | O(nlogn) | O(nlogn) | O(nlogn) | O(n) | 稳定 |
| 快速排序 | O(nlogn) | O(nlogn) | O(n^2) | O(nlogn)~O(n) | 不稳定 |