排序算法小结
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了排序算法小结相关的知识,希望对你有一定的参考价值。
排序算法小结
排序有可以分为以下几类:
(1)、插入排序:直接插入排序、二分法插入排序、希尔排序。
(2)、选择排序:简单选择排序、堆排序。
(3)、交换排序:冒泡排序、快速排序。
(4)、归并排序
(5)、基数排序
一、插入排序
思想:每步将一个待排序的记录,按其顺序码大小插入到前面已经排序的字序列的合适位置,直到全部插入排序完为止。
关键问题:在前面已经排好序的序列中找到合适的插入位置。
方法:
–直接插入排序
–二分插入排序
–希尔排序
1.1 直接插入排序
1 public class InsertionSort { 2 /* 直接插入排序算法 3 * 基本思想: 4 * 每步将一个待排序的记录,按其顺序码大小插入到前面已经排序的序列的合适位置(从后向前找到合适位置后),直到全部插入排序完为止。 5 * 6 * 例子: 32,45,12<-待排序 7 * 1. 12 < 45 : 45 向后移1位 8 * 2. 12 < 32 : 32 向后移1位 9 * 3. 插入 12 10 * 11 * 时间复杂度:最好o(n),平均为o(n^2) 12 */ 13 public static void sort (int[] arrs){ 14 int length = arrs.length; 15 for (int i =1;i<length;i++){ 16 int temp = arrs[i]; // 带插入数据 17 int j=0; 18 for (j = i-1; j>=0; j--) { //前面已经排序的序列 19 // 将大于temp的往后移动一位 20 if(arrs[j]>temp){ 21 arrs[j+1] = arrs[j]; 22 }else{ 23 break; 24 } 25 } 26 arrs[j+1] = temp; 27 } 28 } 29 }
1.2 二分插入排序
1 public class BarnarySort { 2 3 /* 二分法插入排序 4 * 基本思想: 5 * 二分法插入排序的思想和直接插入一样,只是找合适的插入位置的方式不同; 6 * 这里是按二分法找到合适的位置,可以减少比较的次数。 7 * 例子: 8 * [15 27 36 53 69] 42 //left =15 mid = 36 right = 69 9 * 1) --> 42>36 //left =53 mid =53 right =69 10 * 2) --> 42<53 //left =53 right =36 right<left break; 11 * 3) --> [15 27 36 42 53 69] 12 * 13 * 二分法插入排序也是稳定的,时间复杂度 o(n^2)。 14 */ 15 public static void sort(int[] arrs) { 16 for (int i = 0; i < arrs.length; i++) { 17 int temp = arrs[i]; 18 int left = 0; 19 int right = i-1; 20 int mid = 0; 21 while(left<=right){ 22 mid = (left+right)/2; 23 if(temp<arrs[mid]){ 24 right = mid-1; 25 }else{ 26 left = mid+1; 27 } 28 } 29 for (int j = i-1; j >= left; j--) { 30 arrs[j+1] = arrs[j]; 31 } 32 if(left != i){ 33 arrs[left] = temp; 34 } 35 } 36 } 37 }
1.3 希尔排序
1 public class shellSort { 2 3 /* 希尔排序 4 * 基本思想: 5 * 先取一个小于n的整数d1作为第一个增量,把文件的全部记录分成d1个组。 6 * 所有距离为d1的倍数的记录放在同一个组中。先在各组内进行直接插入排序; 7 * 然后,取第二个增量d2<d1重复上述的分组和排序,直至所取的增量dt=1(dt<dt-l<…<d2<d1); 8 * 即所有记录放在同一组中进行直接插入排序为止。该方法实质上是一种分组插入方法。 9 * 例子: dn = dn-1 /2; d1 = arr.length/2 10 * 11 * 希尔排序是不稳定的,时间复杂度 o(nlogn)。 12 */ 13 14 public static void sort(int[] arr){ 15 int d= arr.length; 16 while(true){ 17 d= d/2; 18 for(int x =0;x<d;x++){ 19 for(int i=x+d;i<arr.length;i=i+d){ 20 int tmp = arr[i]; 21 int j= 0; 22 for(j= i-d;j>=0 && arr[j]>tmp;j = j-d){ 23 arr[j+d] = arr[j]; 24 } 25 arr[j+d] = tmp; 26 } 27 } 28 if(d == 1){ 29 break; 30 } 31 } 32 } 33 }
二、选择排序
思想:每趟从待排序的记录序列中选择关键字最小的记录放置到已排序表的最前位置,直到全部排完。
关键问题:在剩余的待排序记录序列中找到最小关键码记录。
方法:
–直接选择排序
–堆排序
2.1 直接选择排序
1 public class SelectionSort { 2 /* 选择排序算法 3 * 基本思想:在要排序的一组数中,选出最小的一个数与第一个位置的数交换; 4 * 然后在剩下的数当中再找最小的与第二个位置的数交换,如此循环到倒数第二个数和最后一个数比较为止。 5 * 例子: 57 68 52 6 * 1. 最小值为52,与第一个交换 7 * 2. 最小值为57,与第二个交换 8 * 3.68为最小值,无需交互 9 * 10 * 简单选择排序是不稳定的排序,时间复杂度 O(n^2)。 11 */ 12 public static void sort(int[] arrs) { 13 for (int i = 0;i<arrs.length;i++){ 14 int min = arrs[i]; 15 int j =0; 16 for(j = i+1;j<arrs.length;j++){ 17 if (arrs[j]< min){ 18 min = arrs[j]; 19 } 20 } 21 arrs[j] = arrs[i]; 22 arrs[i] = min; 23 } 24 } 25 26 }
2.2 堆排序
例子: 初始序列:46,79,56,38,40,84
1 public class HeapSort { 2 3 /* 堆排序 4 * 堆排序是一种树形选择排序,是对直接选择排序的有效改进。 5 * 堆的定义下:具有n个元素的序列 (h1,h2,...,hn); 6 * 当且仅当满足(hi>=h2i,hi>=2i+1)或(hi<=h2i,hi<=2i+1) (i=1,2,...,n/2)时称之为堆。 7 * 在这里只讨论满足前者条件的堆。由堆的定义可以看出,堆顶元素(即第一个元素)必为最大项(大顶堆)。 8 * 完全二叉树可以很直观地表示堆的结构。堆顶为根,其它为左子树、右子树。 9 * 思想: 10 * 初始时把要排序的数的序列看作是一棵顺序存储的二叉树, 11 * 调整它们的存储序,使之成为一个堆,这时堆的根节点的数最大。 12 * 然后将根节点与堆的最后一个节点交换。然后对前面(n-1)个数重新调整使之成为堆。 13 * 依此类推,直到只有两个节点的堆,并对它们作交换,最后得到有n个节点的有序序列。 14 * 从算法描述来看,堆排序需要两个过程,一是建立堆,二是堆顶与堆的最后一个元素交换位置。 15 * 所以堆排序有两个函数组成。 16 * 一是建堆的渗透函数, 17 * 二是反复调用渗透函数实现排序的函数。 18 * 19 * 堆排序是一种不稳定的排序算法,堆排序的最坏时间复杂度为O(nlogn) 20 */ 21 public static void sort(int[] arr){ 22 int len = arr.length; 23 for(int i =0;i<len;i++){ //循环建堆 24 buildheap(arr,0,len-1-i); //建堆 25 swap(arr,0,len-1-i); // 交换根节点和最后一个节点 26 } 27 } 28 29 public static void swap(int[] arr,int start,int tar){ 30 int temp = arr[tar]; 31 arr[tar] = arr[start]; 32 arr[start] = temp; 33 } 34 35 public static void buildheap(int[] arr,int start,int end){ 36 //从最后一节点的父节点开始建堆 37 for(int i = (end-1)/2;i>=0;i--){ 38 int k =i; 39 //k节点的左右子节点为 2k+1,2k+2 (索引从0开始) 40 while(k*2+1<=end){ 41 int bigchild = 2*k+1; 42 if(bigchild<end){ //右节点存在 43 if(arr[bigchild]<arr[bigchild+1]){ 44 bigchild++; //找出最大的子节点 45 } 46 } 47 if(arr[k]<arr[bigchild]){ 48 swap(arr,k,bigchild); 49 k = bigchild; 50 }else{break;} 51 } 52 } 53 } 54 }
三、交换排序
3.1 冒泡排序
1 public class BubbleSort { 2 3 /* 冒泡排序 4 * 基本思想: 5 * 在要排序的一组数中,对当前还未排好序的范围内的全部数, 6 * 自上而下对相邻的两个数依次进行比较和调整,让较大的数往下沉,较小的往上冒。 7 * 即:每当两相邻的数比较后发现它们的排序与排序要求相反时,就将它们互换。 8 * 例子: 9 * 32,74,13 10 * 一趟冒泡排序后 变成 : 32,13,74 11 * 12 * 冒泡排序是一种稳定的排序方法,平均时间复杂度为O(n^2)。 13 */ 14 public static void sort(int[] arrs) { 15 for (int i=0;i<arrs.length;i++){ 16 for(int j=0;j<(arrs.length-i-1);j++){ 17 if (arrs[j]>arrs[j+1]){ 18 int tmp = arrs[j]; 19 arrs[j] = arrs[j+1]; 20 arrs[j+1] = tmp; 21 } 22 } 23 } 24 } 25 26 }
3.2 快速排序
1 public class QuickSort { 2 /* 快速排序 3 * 基本思想: 4 * 选择一个基准元素,通常选择第一个元素或者最后一个元素, 5 * 通过一趟扫描,将待排序列分成两部分,一部分比基准元素小,一部分大于等于基准元素, 6 * 此时基准元素在其排好序后的正确位置,然后再用同样的方法递归地排序划分的两部分。 7 * 8 * 例子: 9 * 57, 68 ,19, 32 //选取57 为key 10 * 一趟: 57, 68 ,19, 32 -> 32, 68, 19, 57 -> 19,32,68,57 11 * 12 * 快速排序是不稳定的排序。时间复杂度为O(nlogn)。 13 */ 14 public static void sort(int[] arrs,int start,int end){ 15 int key = start; 16 int i =start; 17 int j=end; 18 if (start<end){ 19 while(i<j){ 20 while(arrs[i]<arrs[key]){ 21 i++; 22 } 23 swap(arrs,key,i); 24 while(arrs[j]>arrs[key]){ 25 j--; 26 } 27 swap(arrs,key,j); 28 } 29 sort(arrs,start,i); 30 sort(arrs,i+1,end); 31 } 32 } 33 34 public static void swap(int[] arrs,int key,int tar){ 35 int tmp = arrs[key]; 36 arrs[key] = arrs[tar]; 37 arrs[tar] = tmp; 38 } 39 40 }
四、归并排序
1 public class MergeSort { 2 3 /* 归并排序 4 * 基本思想: 5 * 归并(Merge)排序法是将两个(或两个以上)有序表合并成一个新的有序表, 6 * 即把待排序序列分为若干个子序列,每个子序列是有序的。然后再把有序子序列合并为整体有序序列。 7 * 例子: 8 * 57 68 59 52 72 28 96 33 9 * 1) --> [57 68] [52 59] [28 72] [33 96] 10 * 2) --> [52 57 59 68] [28 33 72 96] 11 * 3) --> [28 33 52 57 59 68 72 96] 12 * 13 * 时间复杂度为O(nlogn),是稳定的排序方法。 14 */ 15 public static void sort(int[] arrs,int start,int end){ 16 if (start<end){ 17 int middle = (start+end)/2; 18 sort(arrs,start,middle); 19 sort(arrs,middle+1,end); 20 merge(arrs,middle,start,end); 21 } 22 } 23 24 public static void merge(int[] arrs,int middle,int start,int end){ 25 int[] newarr = new int[arrs.length]; 26 int mid = middle+1; //右边的起始位置 27 int tmp = start; 28 int third = start; 29 while(start<=middle && mid<=end){ 30 //从两个数组中选取较小的数放入中间数组 31 if(arrs[start]<=arrs[mid]){ 32 newarr[third] = arrs[start]; 33 start++; 34 }else{ 35 newarr[third] = arrs[mid]; 36 mid++; 37 } 38 third++; 39 } 40 //将剩余的部分放入中间数组 41 while(start<=middle){ 42 newarr[third] = arrs[start]; 43 third++; 44 start++; 45 } 46 while(mid<=end){ 47 newarr[third] = arrs[mid]; 48 third++; 49 mid++; 50 } 51 //将中间数组复制回原数组 52 while(tmp<=end){ 53 arrs[tmp] = newarr[tmp]; 54 tmp++; 55 } 56 } 57 }
五、基数排序
1 import java.util.ArrayList; 2 import java.util.List; 3 4 public class radixSort { 5 6 /* 基数排序 7 * 基本思想: 8 * 将所有待比较数值(正整数)统一为同样的数位长度,数位较短的数前面补零。 9 * 然后,从最低位开始,依次进行一次排序。这样从最低位排序一直到最高位排序完成以后,数列就变成一个有序序列。 10 * 11 * 例子: 12 * [135 242 192 93 345 11 24 19] //基数为10 13 * 14 * 1) 个位排序 [11 242 192 93 24 135 345 19] 15 * 2) 十位排序 [11 19 24 135 242 345 192 93] 16 * 3) 百位排序 [11 19 24 93 135 192 242 345] 17 * 18 * 基数排序是稳定的排序算法,基数排序的时间复杂度为O(d(n+r)),d为位数,r为基数。 19 */ 20 21 public static void sort(int[] arr){ 22 int max = arr[0]; 23 for(int i=0;i<arr.length;i++){ 24 if (arr[i]>max){ 25 max = arr[i]; 26 } 27 } 28 int times= 0; 29 while(max>0){ 30 max= max/10; 31 times++; 32 } 33 List<ArrayList<Integer>> list = new ArrayList<ArrayList<Integer>>(); 34 for(int i=0;i<10;i++){ 35 ArrayList<Integer> tmplist = new ArrayList<Integer>(); 36 list.add(tmplist); 37 } 38 for(int i= 0;i<times;i++){ 39 for(int j=0;j<arr.length;j++){ 40 int x = arr[j]%(int)Math.pow(10, i+1)/(int)Math.pow(10, i); 41 ArrayList<Integer> tmp = list.get(x); 42 tmp.add(arr[j]); 43 list.set(x, tmp); 44 } 45 int count = 0; 46 for(ArrayList<Integer> tmp : list){ 47 if(!tmp.isEmpty()){ 48 for(Integer num: tmp){ 49 arr[count] = num; 50 count++; 51 } 52 } 53 } 54 for(ArrayList<Integer> tmp : list){ 55 tmp.clear(); 56 } 57 } 58 59 } 60 61 }
=========================================================================
测试工具类
1 import java.util.*; 2 public class sorttest { 3 4 public static void arrayprint(int[] arrs){ 5 int leng = arrs.length; 6 for (int i = 0;i<leng;i++) 7 { 8 System.out.println("element "+ i+" -> "+arrs[i]); 9 } 10 } 11 12 public static void main(String[] args) { 13 Scanner sc = new Scanner(System.in); 14 List<Integer> ints = new ArrayList<Integer>(); 15 System.out.println("input array elements,use <ctrl> + <d> to end the input!"); 16 while(sc.hasNextInt()){ 17 int tmp = sc.nextInt(); 18 System.out.println("add to array: "+tmp); 19 ints.add(tmp); 20 } 21 sc.close(); 22 int[] arrs = new int[ints.size()]; 23 for(int i = 0;i<ints.size();i++){ 24 arrs[i] = ints.get(i); 25 } 26 System.out.println("before array sorted..."); 27 sorttest.arrayprint(arrs); 28 /* 29 * here use sort function for parameter: arrs 30 */ 31 System.out.println("after array sorted..."); 32 sorttest.arrayprint(arrs); 33 } 34 35 }
以上是关于排序算法小结的主要内容,如果未能解决你的问题,请参考以下文章