三种时间复杂度为O(n2)的排序算法
插入排序
插入排序的主要思想是:每一次得到一个新的元素,就和原来已经排序好的序列对比,然后将这个新的元素插入到正确的位置,具体的代码实现:
void insertSort(int a[],int length) { if(a==NULL||length<=0) return; for(int i=1;i<length;i++) { int j=i; while(j-1>=0&&a[j-1]>a[j]) { int tmp=a[j-1]; a[j-1]=a[j]; a[j]=tmp; j--; } } }
插入排序的最差情况,这里做的是从小到大的排列,假设对于第k次循环,需要比较的k前的元素和第k个的大小,需要将第k个元素移动到小于等于的位置,所有对于最差的情况,应该是该数组逆序排列,从第i(i>=1)个元素开始,每一个元素,要移动i位,最差的时间复杂度应该是1+2+3+....+n-1 ,所以应该是O(n2).
最好的时间复杂读,是已经排好序,也就是只需要遍历一遍,时间复杂度为O(n);
同样的道理,平均情况应该也是O(n2).
冒泡排序
冒泡排序的主要思想是,小的下沉,大的上浮。
代码实现如下:
void bubSort(int a[],int length) { if(a==NULL||length<=0) return; for(int i=1;i<length;i++) { for(int j=i;j>0;j--) { if(a[j]<a[j-1]) { int tmp=a[j]; a[j]=a[j-1]; a[j-1]=tmp; } } } }
通过代码可以看出,冒泡排序的时间复杂度为O(n2)
选择排序
主要的思想是:从数组中选择一个最小的,放在最前的位置,然后选择次小的,依次下去,这样就形成了一个有序的数组。
代码实现:
void selectSort(int a[],int length) { if(a==NULL||length<=0) return; for(int i=0;i<length;i++) { int min=a[i]; int pos=i; for(int j=i+1;j<length;j++) { if(a[j]<min) { min=a[j]; pos=j; } } //交换最小的 int tmp=a[i]; a[i]=min; a[pos]=tmp; } }
可以看出,,选择排序最好、最差、平均都是O(n2);
一下是三种简单排序算法的比较
Shell排序
主要的思想:Shell排序是插入排序的改进,由于插入排序是相邻元素之间的比较,Shell排序主要的是将比较的元素进行非增量比较,也就是将元素进行分为多个序列,然后进行比较,但是要注意的是,在最后,还要进行一次增量为1的比较,也就是常规的插入排序。
代码实现
void shellInsertSort(int a[],int length,int incr) { for(int i=incr;i<length;i+=incr) { int j=i; while(j-incr>=0&&a[j-incr]>a[j]) { int tmp=a[j-1]; a[j-1]=a[j]; a[j]=tmp; j-=incr; } } } void shellSort(int a[],int length) { for(int i=length;i>2;i=i/2) for(int j=0;j<i;j++) shellInsertSort(a,length-j,i); shellInsertSort(a,length,1); }
Shell排序的最好、最坏时间复杂度为O(n2),平均时间复杂为O(n1.5)
快速排序
快速排序的主要思想:主要是利用分治的思想,将数组分为两部分,左边的部门小于a[k],右边的元素大于等于a[k-1],然后重复以上步骤。
代码实现:
public class QuickSort { public static void quickSort(int arr[],int _left,int _right){ int left = _left; int right = _right; int temp = 0; if(left <= right){ //待排序的元素至少有两个的情况 temp = arr[left]; //待排序的第一个元素作为基准元素 while(left != right){ //从左右两边交替扫描,直到left = right while(right > left && arr[right] >= temp) right --; //从右往左扫描,找到第一个比基准元素小的元素 arr[left] = arr[right]; //找到这种元素arr[right]后与arr[left]交换 while(left < right && arr[left] <= temp) left ++; //从左往右扫描,找到第一个比基准元素大的元素 arr[right] = arr[left]; //找到这种元素arr[left]后,与arr[right]交换 } arr[right] = temp; //基准元素归位 quickSort(arr,_left,left-1); //对基准元素左边的元素进行递归排序 quickSort(arr, right+1,_right); //对基准元素右边的进行递归排序 } } public static void main(String[] args) { int array[] = {10,5,3,1,7,2,8}; System.out.println("排序之前:"); for(int element : array){ System.out.print(element+" "); } quickSort(array,0,array.length-1); System.out.println("\n排序之后:"); for(int element : array){ System.out.print(element+" "); } } }
快速排序的最好和平均时间O(nlogN),最差情况是O(n2).
堆排序
主要的思想:利用堆的性质。
堆排序在上几节中已经实现,这里只是讲解最坏、最差、平均的时间复杂度为O(nlogN);
归并排序
void mergeSort(int a[],int tmp[],int left,int right) { int mid=(left+right)/2; if(left==right) return; mergeSort(a,tmp,left,mid); mergeSort(a,tmp,mid,right); for(int i=left;i<=right;i++) { tmp[i]=a[i]; } int i1=left,j=mid+1; for(int i=left;i<=right;i++) { if(i1==mid+1){ //这里左边的数组使用完毕 a[i]=tmp[j++]; } else if(j>right) { a[i]=tmp[i1++]; } else if(a[i1]<a[j]) { a[i]=a[i1++]; } else { a[i]=a[j++]; } } }对于归并排序,划分的深度为logN,无论好坏,平均,这个算法的平均复杂度为(nlongN)