一、插入排序
1.直接插入排序
算法稳定,时间复杂度为O(n^2),空间移动复杂度为O(n2)
如果序列是有序的,最好的时间复杂度为O(n)
即该算法与初始数据的排序序列有关。
void insertSort(int data[],int n) { for(int i=1;i<n;i++) { int j = i - 1; int temp = data[i]; while(j>=0&&data[j]>temp) { data[j+1] = data[j]; j--; } data[j+1] = temp; } }
2.折半插入排序
查找插入位置采用折半查找法。
算法稳定,时间复杂度为O(nlog2n),空间移动复杂度为O(n2)
折半插入算法与初始数据的顺序是有关系的。数据有序的时候,折半查找的效率反而降低。
void BinaryinsertSort(int data[],int n) { for(int i=1;i<n;i++) { int left = 0; int right = i-1; int temp = data[i]; while(left<=right) { int mid = (left+right)/2 ; if(data[mid]>temp) //判断是否影响稳定性。
rigth = mid - 1; else left = mid + 1; } for(int j=i-1;j>=left;j--) data[j+1] = data[j]; data[left] = temp; } }
3.希尔排序
将待排数据分组,组内进行直接插入排序。逐步减小分组数,最后再整体进行直接插入排序。
希尔排序的时间复杂度为介于O(nlog2n)与O(n*n)之间,大约为O(n1.3);
希尔排序算法是不稳定的。
void ShellSort(int data[],int n) { int d = n/2; while(d>=1) { for(int k=0;k<d;k++) { for(int i=k+d;i<n;i+=d) { int temp = data[i]; int j=i-d; while(j>=k&&data[j]>temp) { data[j+d] = data[j]; j-=d; } data[j+d]=temp; } } d = d/2; } }
二、交换排序
1.冒泡排序
时间复杂度为O(n*n),是稳定的排序算法。
其排序效果与初始序列的顺序有关系。
程序如下:
最原始的冒泡排序算法:
void BubbleSort(int data[ ],int n) { for(int i=0;i<n-1;++i) { for(int j=1;j<n-i;++j) { if(data[j-1]>data[j]) { int temp = data[j-1]; data[j-1] = data[j]; data[j] = temp; } } } }
改进后的冒泡排序算法:
最好的情况先是数据序列本来就是有序的,只需要进行n-1次的比较,不需要进行交换。
即仅需要进行0次的交换。
void BubbleSort(int data[ ],int n) { for(int i=0;i<n-1;++i) { int flag = 0; for(int j=1;j<n-i;++j) { if(data[j-1]>data[j]) { flag = 1; int temp = data[j-1]; data[j-1] = data[j]; data[j] = temp; } } if(0==flag) return; } }
2.快速排序
分治法的思想,最坏的情况是待排数据时有序的时候,此时会造成轴元素的一侧子序列的长度为0,另一侧的长度为n,此时时间复杂度为O(n*n)
空间复杂度主要是递归调用的栈的开销,最好的时候是O(logn),最坏的情况是O(n).
平均的时间复杂度为:O(nlogn);
该算法是不稳定的。
大量数据的排序,最好使用快速排序。这样带来的促进效果会更加显著。
代码如下:
int partition(T data[],int left,int right) { int p = data[left]; while(left<=right) { while(left<=right&&data[left]<=p) left++; while(left<=right&&data[right]>=p) right--; if(left<right) { swap(data[left],data[right]); left++;right--; } } swap(p,data[right]); return right; } void quicksort(int data[],int left,int right) { if(left<right) { int p = partion(data,left,right); quicksort(data,left,p-1); quicksort(data,p+1,right); } }
或者
#include<stdio.h> #include<string.h> #include<stdlib.h> void swap(int *a,int *b) { int temp = *a; *a = *b; *b = temp; } int partation(int data[],int left,int right) { int p = data[left]; int start = left; while(left<=right) { while(left<=right&&data[left]<=p) left++; while(left<=right&&data[right]>p) right--; if(left<right) { swap(&data[left],&data[right]); left++;right--; } } swap(&data[start],&data[right]); return right; } void quicksort(int data[],int left,int right) { int p; if(left<right) { p = partation(data,left,right); quicksort(data,left,p-1); quicksort(data,p+1,right); } } int main() { int n; int i; int arr[100]; while(scanf("%d",&n)!=EOF) { for(i=0;i<n;i++) scanf("%d",&arr[i]); quicksort(arr,0,n-1); for(i=0;i<n;i++) printf("%d ",arr[i]); printf(" "); } return 0; }
三、选择排序
1.简单选择排序
时间复杂度为O(n*n),空间复杂度为O(1)
是不稳定的排序算法。
程序如下:
void SelectionSort(int data[ ],int n) { for(int i=1;i<n;++i) { int k = i - 1; for(int j = i; j<n;++j) { if(data[j]<data[k]) k = j; } if(k!=i-1) { swap(data[i-1],data[k]); } }
2.堆排序
建堆的时间复杂度为O(n)
最大堆的调整函数为shiftdown()函数。
每次最多执行O(logn)次数据的交换,所以其时间复杂度为O(nlogn).
空间开销是O(1).
该算法是不稳定的。
四、归并排序
最坏的情况下的时间复杂度也为O(nlogn),算法是稳定的。
空间复杂度为O(n).
原始数据的排列情况对该排序算法的复杂度没有影响。
程序如下,如下的程序时二路归并排序,所谓的二路归并排序指的是,每次迭代都将待排序列分割为两个等长的子序列,
就称为二路归并排序:
合并一个序列中的两个有序的序列:
void Merg(int data[ ],int start,int mid,int end) { int len1 = mid - start + 1; int len2 = end - mid; int i,j,k; for(k=start;k<end;++k) { if(i==len1 || j==len2) break; if(left[i]<=right[j]) data[k]=left[i++]; else data[k]=right[j++]; while(i<len1) data[k++] = left[i++]; while(j<len2) data[k++] = right[j++]; } }
//归并排序实现:
void MergSort(int data[ ],int start,int end) { if(start < end) { int mid = (start + end)/2; MergSort(data,start,mid); MergSort(data,mid+1,end); Merg(data,start,mid,end); } }