冒泡排序
冒泡排序是一种简单的排序算法。它重复地走访过要排序的数列,一次比较两个元素,如果他们的顺序错误就把他们交换过来。走访数列的工作是重复地进行直到没有再需要交换,也就是说该数列已经排序完成。这个算法的名字由来是因为越小的元素会经由交换慢慢“浮”到数列的顶端。
冒泡排序的示例:
冒泡排序的算法实现如下:【排序后,数组从小到大排列】
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
|
public static void bubbleSort(int[] numbers) { int temp = 0; int size = numbers.length; for(int i = 0 ; i < size-1; i ++) { for(int j = 0 ;j < size-1-i ; j++) { if(numbers[j] > numbers[j+1]) { temp = numbers[j]; numbers[j] = numbers[j+1]; numbers[j+1] = temp; } } } }
|
快速排序
快速排序的基本思想:
通过一趟排序将待排序记录分割成独立的两部分,其中一部分记录的关键字均比另一部分关键字小,则分别对这两部分继续进行排序,直到整个序列有序。
快速排序的示例:
(a)一趟排序的过程:
(b)排序的全过程:
把整个序列看做一个数组,把第零个位置看做中轴,和最后一个比,如果比它小交换,比它大不做任何处理;交换了以后再和小的那端比,比它小不交换,比他大交换。这样循环往复,一趟排序完成,左边就是比中轴小的,右边就是比中轴大的,然后再用分治法,分别对这两个独立的数组进行排序。
代码实现如下:
查找中轴(最低位作为中轴)所在位置:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
|
public static int getMiddle(int[] numbers, int low,int high) { int temp = numbers[low]; while(low < high) { while(low < high && numbers[high] > temp) { high--; } numbers[low] = numbers[high]; while(low < high && numbers[low] < temp) { low++; } numbers[high] = numbers[low] ; } numbers[low] = temp ; return low ; }
|
递归形式的分治排序算法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
|
public static void quickSort(int[] numbers,int low,int high) { if(low < high) { int middle = getMiddle(numbers,low,high); quickSort(numbers, low, middle-1); quickSort(numbers, middle+1, high); }
}
|
快速排序提供方法调用:
1 2 3 4 5 6 7 8 9 10 11
|
public static void quick(int[] numbers) { if(numbers.length > 0) { quickSort(numbers, 0, numbers.length-1); } }
|
分析:
快速排序是通常被认为在同数量级(O(nlog2n))的排序方法中平均性能最好的。但若初始序列按关键码有序或基本有序时,快排序反而蜕化为冒泡排序。为改进之,通常以“三者取中法”来选取基准记录,即将排序区间的两个端点与中点三个记录关键码居中的调整为支点记录。快速排序是一个不稳定的排序方法。
方法测试
打印函数:
1 2 3 4 5 6 7 8
| public static void printArr(int[] numbers) { for(int i = 0 ; i < numbers.length ; i ++ ) { System.out.print(numbers[i] + ","); } System.out.println(""); }
|
测试:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| public static void main(String[] args) { int[] numbers = {10,20,15,0,6,7,2,1,-5,55}; System.out.print("排序前:"); printArr(numbers);
bubbleSort(numbers); System.out.print("冒泡排序后:"); printArr(numbers);
quick(numbers); System.out.print("快速排序后:"); printArr(numbers); }
|
结果:
排序前:10,20,15,0,6,7,2,1,-5,55,
冒泡排序后:-5,0,1,2,6,7,10,15,20,55,
快速排序后:-5,0,1,2,6,7,10,15,20,55,
选择排序
1、基本思想:在要排序的一组数中,选出最小的一个数与第一个位置的数交换;然后在剩下的数当中再找最小的与第二个位置的数交换,如此循环到倒数第二个数和最后一个数比较为止。
2、实例:
3、算法实现:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
|
public static void selectSort(int[] numbers) { int size = numbers.length; int temp = 0 ;
for(int i = 0 ; i < size ; i++) { int k = i; for(int j = size -1 ; j > i ; j--) { if(numbers[j] < numbers[k]) { k = j; } } temp = numbers[i]; numbers[i] = numbers[k]; numbers[k] = temp; } }
|
插入排序
1、基本思想:每步将一个待排序的记录,按其顺序码大小插入到前面已经排序的字序列的合适位置(从后向前找到合适位置后),直到全部插入排序完为止。
2、实例:
3、算法实现:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
|
public static void insertSort(int[] numbers) { int size = numbers.length; int temp = 0 ; int j = 0;
for(int i = 0 ; i < size ; i++) { temp = numbers[i]; for(j = i ; j > 0 && temp < numbers[j-1] ; j --) { numbers[j] = numbers[j-1]; } numbers[j] = temp; } }
|
4、效率:
时间复杂度:O(n^2).
希尔算法
1、基本思想:
先将整个待排序的记录序列分割成为若干子序列分别进行直接插入排序,待整个序列中的记录“基本有序”时,再对全体记录进行依次直接插入排序。
2、操作方法:
1、选择一个增量序列t1,t2,…,tk,其中ti>tj,tk=1;
2、按增量序列个数k,对序列进行k 趟排序;
3、每趟排序,根据对应的增量ti,将待排序列分割成若干长度为m 的子序列,分别对各子表进行直接插入排序。仅增量因子为1 时,整个序列作为一个表来处理,表长度即为整个序列的长度。
希尔排序的示例:
3、**算法实现:**
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37
|
public static void shellSort(int[] data) { int j = 0; int temp = 0; for (int increment = data.length / 2; increment > 0; increment /= 2) { for (int i = increment; i < data.length; i++) { temp = data[i]; for (j = i; j >= increment; j -= increment) { if(temp > data[j - increment]) { data[j] = data[j - increment]; } else { break; }
} data[j] = temp; }
} }
|
4、效率:
时间复杂度:O(n^2).
归并排序算法
基本思想:
归并(Merge)排序法是将两个(或两个以上)有序表合并成一个新的有序表,即把待排序序列分为若干个子序列,每个子序列是有序的。然后再把有序子序列合并为整体有序序列。
归并排序示例:
合并方法:
设r[i…n]由两个有序子表r[i…m]和r[m+1…n]组成,两个子表长度分别为n-i +1、n-m。
1 2 3 4 5 6 7 8 9
| 1、j=m+1;k=i;i=i; //置两个子表的起始下标及辅助数组的起始下标 2、若i>m 或j>n,转⑷ //其中一个子表已合并完,比较选取结束 3、//选取r[i]和r[j]较小的存入辅助数组rf 如果r[i]<r[j],rf[k]=r[i]; i++; k++; 转⑵ 否则,rf[k]=r[j]; j++; k++; 转⑵ 4、//将尚未处理完的子表中元素存入rf 如果i<=m,将r[i…m]存入rf[k…n] //前一子表非空 如果j<=n , 将r[j…n] 存入rf[k…n] //后一子表非空 5、合并结束。
|
算法实现:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58
|
public static int[] sort(int[] nums, int low, int high) { int mid = (low + high) / 2; if (low < high) { sort(nums, low, mid); sort(nums, mid + 1, high); merge(nums, low, mid, high); } return nums; }
public static void merge(int[] nums, int low, int mid, int high) { int[] temp = new int[high - low + 1]; int i = low; int j = mid + 1; int k = 0;
while (i <= mid && j <= high) { if (nums[i] < nums[j]) { temp[k++] = nums[i++]; } else { temp[k++] = nums[j++]; } }
while (i <= mid) { temp[k++] = nums[i++]; }
while (j <= high) { temp[k++] = nums[j++]; }
for (int k2 = 0; k2 < temp.length; k2++) { nums[k2 + low] = temp[k2]; } }
|
堆排序算法
1、基本思想:
堆排序是一种树形选择排序,是对直接选择排序的有效改进。
堆的定义下:具有n个元素的序列 (h1,h2,…,hn),当且仅当满足(hi>=h2i,hi>=2i+1)或(hi<=h2i,hi<=2i+1) (i=1,2,…,n/2)时称之为堆。在这里只讨论满足前者条件的堆。由堆的定义可以看出,堆顶元素(即第一个元素)必为最大项(大顶堆)。完全二 叉树可以很直观地表示堆的结构。堆顶为根,其它为左子树、右子树。
思想:初始时把要排序的数的序列看作是一棵顺序存储的二叉树,调整它们的存储序,使之成为一个 堆,这时堆的根节点的数最大。然后将根节点与堆的最后一个节点交换。然后对前面(n-1)个数重新调整使之成为堆。依此类推,直到只有两个节点的堆,并对 它们作交换,最后得到有n个节点的有序序列。从算法描述来看,堆排序需要两个过程,一是建立堆,二是堆顶与堆的最后一个元素交换位置。所以堆排序有两个函数组成。一是建堆的渗透函数,二是反复调用渗透函数实现排序的函数。
2、实例:
初始序列:46,79,56,38,40,84
建堆:
交换,从堆中踢出最大数:
依次类推:最后堆中剩余的最后两个结点交换,踢出一个,排序完成。
3.算法实现:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50
| public class HeapSort { public static void main(String[] args) { int[] a={49,38,65,97,76,13,27,49,78,34,12,64}; int arrayLength=a.length; for(int i=0;i<arrayLength-1;i++){ buildMaxHeap(a,arrayLength-1-i); swap(a,0,arrayLength-1-i); System.out.println(Arrays.toString(a)); } } public static void buildMaxHeap(int[] data, int lastIndex){ for(int i=(lastIndex-1)/2;i>=0;i--){ int k=i; while(k*2+1<=lastIndex){ int biggerIndex=2*k+1; if(biggerIndex<lastIndex){ if(data[biggerIndex]<data[biggerIndex+1]){ biggerIndex++; } } if(data[k]<data[biggerIndex]){ swap(data,k,biggerIndex); k=biggerIndex; }else{ break; } } } } private static void swap(int[] data, int i, int j) { int tmp=data[i]; data[i]=data[j]; data[j]=tmp; } }
|
各种算法的时间复杂度