一、插入排序
基本思想:每一趟将一个待排序的记录,按待排序的元素插入到已经排好序的一组记录的适当位置上,直到全部待排序记录全部插入为止。
1)直接插入排序
排序过程:
1、将待排序数组arr[1…n]看作两个集合,arr[1]为有序集合中元素,arr[2…n]为无序集合中元素,a[0]用来临时存放当前待排序记录
2、外层循环每次从无序集合中选择一个待插入元素(n-1次),每次使用顺序查找法,内层循环查找arr[i]在有序集合中的位置(将有序集合中大于待插入元素的记录后移一位)。
//直接插入排序
void Insert_Sort(int *arr,int n){
int j = 0;
for(int i = 2; i <= n; ++i){
if(arr[i] < arr[i-1]){
arr[0] = arr[i];
arr[i] = arr[i-1];
for(j = i-2; arr[0] < arr[j];--j)
arr[j+1] = arr[j];
arr[j+1] = arr[0];
}
}
}
算法特点:
1、稳定排序;
2、适用于顺序存储结构和链式存储结构;
3、适用于初始记录基本有序的情况,当初始记录无序,n较大时,此算法时间复杂度较高,不宜采用。
稳定排序:指的是排序之后原来相同大小的元素相对位置没有改变。
2)希尔排序
当待排序记录个数越少、待排序记录中逆序越少,直接插入排序算法的效率越高。希尔排序通过将待排序记录进行分组来减少记录数量,通过对分组后的每个小组进行直接插入排序来减少逆序对的数量。
//希尔排序
//步长序列计算公式 n/2^k n为排序规模 k取1,2,3,4 ... 当步长为1时为止
void shell_insert(int arr[],int n,int d){
int j;
for(int i = d+1; i <= n; i++){
arr[0] = arr[i];
for(j = i; j > d && arr[0] < arr[j-d]; j -= d){
arr[j] = arr[j-d];
}
arr[j] = arr[0];
}
}
void shell_sort(int arr[],int n){
for(int gap = n / 2; gap > 0; gap /= 2){
shell_insert(arr,n,gap);
}
}
算法特点:
1、不稳定排序;
2、只能用于顺序结构,不能用于链式结构;
3、增量可以有各种取法,但应该使增量序列中的值没有除1之外的公因子,并且最后一个增量值必须是1;
4、总的比较次数和移动次数比直接插入排序要少,n越大,效果越明显,适用于初始记录无序、n较大的情况。
二、选择排序
基本思想:每一趟排序从待排序的记录中选出关键字最小的记录,按顺序放在已排序的记录中,直到全部排完为止。
1)简单选择排序
//简单选择排序
void select_sort(int arr[],int n){
int k;
for(int i = 1; i < n; i++){
k = i;
for(int j = i+1; j <= n; j++){
if(arr[k] > arr[j])
k = j;
}
if(k != i){
arr[0] = arr[i]; arr[i] = arr[k]; arr[k] = arr[0];
}
}
}
算法特点:
1、算法本身是稳定排序,也可以变成是不稳定排序;
2、可以用于链式存储结构;
3、移动次数少,当每一个记录占用的空间较多时,此方法比直接插入排序快。
2)堆排序
每次将堆顶元素取出,与末尾元素交换,然后按照要求调整前n-1个元素,使其仍然成堆,重复上述过程,直到剩余元素为1时为止。
//调整堆
void heap_adjust(int arr[],int low,int high){
arr[0] = arr[low];
for(int i = 2*low; i <= high; i *= 2){
if(i<high && arr[i] < arr[i+1])
i++;
if(arr[0] >= arr[i])
break;
arr[low] = arr[i];low = i;
}
arr[low] = arr[0];
}
//初建堆
void creat_heap(int arr[],int n){
for(int i = n / 2; i > 0; i--){
heap_adjust(arr,i,n);
}
}
//堆排序
void heap_sort(int arr[],int n){
creat_heap(arr,n);
for(int i = n; i > 1; i--){
arr[0] = arr[1];
arr[1] = arr[i];
arr[i] = arr[0];
heap_adjust(arr,1,i-1);
}
}
算法特点:
1、不稳定排序;
2、只能用于顺序结构,不能用于链式结构;
3、初始建堆所需要的比较次数比较多,记录较少时不宜采用,堆排序在最坏情况下的时间复杂度为O(nlog2 n),相对于快速排序最坏情况下的O(n^2)而言是个优点,当记录较多时较为高效。
三、交换排序
基本思想:两两比较待排序记录关键字,当两个关键字不满足次序要求时进行交换,直到整个序列满足要求为止。
1)冒泡排序
两两比较关键字,如逆序则交换顺序,较大关键字逐渐一端移动,直到序列有序。
//冒泡排序
void bubble_sort(int arr[],int n){
int flag = 1 , len = n;
int m = n;
while((m > 0) && (flag == 1)){
flag = 0;
for(int j = 1; j <= m; j++){
if(arr[j] > arr[j+1]){
flag = 1;
arr[0] = arr[j];arr[j] = arr[j+1]; arr[j+1] = arr[0];
}
}
m--;
}
}
算法特点:
1、稳定排序;
2、可用于链式存储结构;
3、记录移动次数较多,算法平均性能比直接插入排序差,当初始记录无序时,n较大时,不宜采用。
2)快速排序
冒泡排序只对相邻两个记录进行比较,因此每次只能消除一个逆序,而快速排序一次交换可消除多个逆序,从而提高排序性能。其主要原理是每次找到待排序组里面的中间值,然后分成左右两个区间,再分别排序这两个区间。
//快速排序
//一趟排序,返回中间位置
int partition(int arr[],int low,int high){
arr[0] = arr[low];
while(low < high){
while((low < high) && arr[high] >= arr[0]) high--;
arr[low] = arr[high];
while((low < high) && arr[low] <= arr[0]) low++;
arr[high] = arr[low];
}
arr[low] = arr[0];
return low;
}
//递归进行排序
void QSort(int arr[],int low,int high){
int pivotloc;
if(low < high){
pivotloc = partition(arr,low,high);
QSort(arr,low,pivotloc-1);
QSort(arr,pivotloc+1,high);
}
}
void quick_sort(int arr[],int n){
QSort(arr,1,n);
}
算法特点:
1、不稳定排序;
2、适用于顺序结构,很难用于链式结构;
3、当n较大时,在平均情况下时所有内部排序方法中最快的一种,适用于初始记录无序,n较大的情况。
四、归并排序
基本思想:
把两个有序的区间结合在一起,假设初始序列含有n个记录,则可看成时n个有序的子序列,每个子序列的长度为1,然后两两并归,得到n/2个长度为2或1的有序子序列,类似于二叉树中的后序遍历,把区间分成两部分,一直分下去直到为1个元素的叶子结点。
//合并相邻位置上的有序表
void Merge(int arr1[],int arr2[],int low,int mid,int high){
int i = low, j = mid+1, k = low;
while(i <= mid && j <= high){
if(arr1[i] <= arr1[j]) arr2[k++] = arr1[i++];
else arr2[k++] = arr1[j++];
}
while(i <= mid) arr2[k++] = arr1[i++];
while(j <= high) arr2[k++] = arr1[j++];
}
void Msort(int arr1[],int arr2[],int low,int high){
int mid; int arr3[high];
if(low == high) arr2[low] = arr1[low];
else{
mid = (low + high) / 2;
Msort(arr1,arr3,low,mid);
Msort(arr1,arr3,mid+1,high);
Merge(arr3,arr2,low,mid,high);
}
}
//归并排序
void Merge_sort(int arr[],int n){
Msort(arr,arr,1,n);
}
算法特点:
1、稳定排序;
2、可用于链式结构,且不需要附加存储空间,但递归实现仍需要开辟相应的递归工作栈。