今年任务很繁重,找工作应是重中之重。。。在此记录下复习基础知识的过程。
排序是程序开发中一种非常常见的操作,是对任意的一组数据经过排序操作后,就可以把他们变成一组按关键字排列的有序序列。对一个排序算法来说,一般从如下3个方面衡量算法的优劣:
时间复杂度:主要是分析关键字的比较次数和记录的移动次数。
空间复杂度:分析排序算法中需要多少辅助内存。
稳定性:若两个记录A和B的关键字值相等,但排序后A、B的先后次序保持不变,则称这种算法是稳定的;反之,就是不稳定的。
排序算法大致有直接插入排序、折半插入排序、Shell排序、归并排序、直接选择排序、堆排序、冒泡排序、快速排序、桶式排序、基数排序等这些种,各个算法都有其优异性,大家不妨自己看看。下面贴上每个算法的简单讲解和实现。
1.直接选择排序(DirectSelectSort):其关键就是对n个数据要进行n-1趟比较,每趟比较的目的就是选择出本趟比较中最小的数据,并将选择出的数据放在本趟中的第一位。实现如下:
1 public static void directSelectSort(int[] data){ 2 int minData = 0 ; 3 int index = 0; 4 for(int i = 0;i < data.length-1; i++){ 5 minData = data[i]; 6 index = i; 7 for(int j = i+1;j<data.length;j++){ 8 if(minData >= data[j]){ 9 minData = data[j]; 10 index = j; 11 } 12 } 13 data[index] = data[i]; 14 data[i]=minData; 15 16 } 17 }
2.堆排序(HeapSort):先说下堆的概念,假设有n个数据元素的序列k0,k1,k2,k3,...,kn-1,当且仅当满足下列关系时,可以将这组数据称为小顶堆,即ki <= k2i+1且 ki<= k2i+2(其中i=0,2,4,...,(n-1)/2);或者,满足如下关系成为大顶堆,即ki >= k2*i+1且 ki >= k2*i+2(其中i=0,2,...,(n-1)/2)。如果将堆排成一棵完全二叉树,则小顶堆的特点是:树中所有节点的值都小于其左右节点的值,且根节点的值最小;而大顶堆相反。堆排序的关键在于:1.建堆(大顶堆或小顶堆)2.拿堆的根节点和最后一个节点交换。
1 public static void heapSort(int[] data){ 2 for(int i = 0;i < data.length-1;i++){ 3 buildMaxHeap(data,data.length-1-i); 4 swap(data,0,data.length-i-1); 5 } 6 } 7 8 public static void buildMaxHeap(int[] data,int lastIndex){ 9 for(int i=(lastIndex-1)/2;i>=0;i--){ 10 //k为父亲节点 11 int k = i; 12 while (k*2+1 <= lastIndex){ 13 int biggerIndex = k*2+1; 14 //求孩子节点最大的一个 15 if(biggerIndex < lastIndex){ 16 if(data[biggerIndex] < data[biggerIndex+1]){ 17 biggerIndex++; 18 } 19 } 20 if(data[k] < data[biggerIndex]){ 21 swap(data,k,biggerIndex); 22 k = biggerIndex; 23 } 24 else{ 25 break; 26 } 27 } 28 } 29 } 30 31 public static void swap(int[] data,int i,int j){ 32 int temp = data[i]; 33 data[i]=data[j]; 34 data[j]=temp; 35 }
3. 冒泡排序(BubbleSort):冒泡排序是最简单的排序算法之一,实现起来也比较简单,其原理就是进行n-1趟比较并交换,小数往上冒,大数往下沉,经过n-1趟之后形成了有序的数列。
1 public static void BubbleSort(int[] data){ 2 for(int i=0;i<data.length-1;i++){ 3 for(int j=0;j<data.length-i-1;j++){ 4 if(data[j]>data[j+1]){ 5 int temp = data[j]; 6 data[j]=data[j+1]; 7 data[j+1]=temp; 8 } 9 } 10 } 11 }
4.快速排序(QuickSort): 快速排序死对 冒泡排序的一种改进,基本思想是:通过一趟排序将要排序的数据分割成独立的两部分,其中一部分的所有数据都比另外一部分的所有数据都要小,然后再按此方法对这两部分数据分别进行快速排序,整个排序过程可以递归进行,以此达到整个数据变成有序序列。
1 public static void quickSort(int[] data,int start,int end){ 2 if(start < end){ 3 int middleIndex = start; 4 int i = start; 5 int j = end + 1; 6 while(true){ 7 while(i<end && data[++i] <= data[middleIndex]); 8 while(j>start && data[--j] >= data[middleIndex]); 9 if(i<j){ 10 int temp = data[i]; 11 data[i] = data[j]; 12 data[j] = temp; 13 } 14 else{ 15 break; 16 } 17 } 18 int temp = data[middleIndex]; 19 data[middleIndex] = data[j]; 20 data[j] = temp; 21 quickSort(data,0,j-1); 22 quickSort(data,j+1,end); 23 } 24 }
5.直接插入排序(DirectInsertSort):直接插入排序的思路很简单,就是依次将带排序的数据元素按其关键字排序的大小插入前面的有序序列。
1 public static void directInsertSort(int[] data){ 2 for(int i = 1;i<data.length;i++){ 3 for(int j = 0;j<i;j++){ 4 if(data[i] < data[j]){ 5 int temp = data[i]; 6 for(int m = i;m>j;m--){ 7 data[m]=data[m-1]; 8 } 9 data[j]=temp; 10 } 11 } 12 } 13 }
6.折半插入排序(BinaryInsertSort):折半插入排序是对直接插入排序的改进,具体操作为:在将一个新元素插入已排好序的数组的过程中,寻找插入点时,将待插入区域的首元素设置为a[low],末元素设置为a[high],则轮比较时将待插入元素与a[m],其中m=(low+high)/2相比较,如果比参考元素小,则选择a[low]到a[m-1]为新的插入区域(即high=m-1),否则选择a[m+1]到a[high]为新的插入区域(即low=m+1),如此直至low<=high不成立,即将此位置之后所有元素后移一位,并将新元素插入a[high+1]。
1 public static void binaryInsertSort(int[] data){ 2 for(int i = 1;i<data.length;i++){ 3 int low = 0; 4 int high = i-1; 5 int temp = data[i]; 6 while(low<=high){ 7 int mid =(low+high)/2; 8 if(data[mid] < temp){ 9 low = mid + 1; 10 } 11 else{ 12 high = mid -1; 13 } 14 } 15 for(int m = i;m>low;m--){ 16 data[m]=data[m-1]; 17 } 18 data[low] = temp; 19 } 20 }