内排序 排序使程序开发中一种常见的操作。将一组杂乱无章的数据按一定的规则将其排列好。使数据得以快速检索到,这就是排序的目的。 对于一个排序算法,一般可以从下面三个方面去衡量算法的优劣:
1) 时间复杂度:主要缝隙关键字的比较次数和移动字数; 2) 空间复杂度:缝隙排序算法中需要多少辅助内存; 3) 稳定性:当两个关键字相同,如果排序完成后两者的顺序保持不变,则是该排序算法是稳定。 排序算法大致可以分为内部算法和外部算法。如果整个排序过程不需要借助于外部储存器(磁盘),所有的操作都在内存中完成,则称之为内部算法。如果参与排序树数据元素非常多,数据量非常大,则计算机必须借助外部储存器(如磁盘),这种排序称为外部排序。
内部排序的分类 一般我们所说排序指的就是内部排序,常见的内部排序又可以分为6大类。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 package sort;class DataWrap implements Comparable <DataWrap > { int data; String flag; public DataWrap (int data, String flag) { this .data = data; this .flag = flag; } public String toString () { return data + flag; } public int compareTo (DataWrap dw) { return this .data > dw.data ? 1 : (this .data == dw.data ? 0 : -1 ); } }
1.1 选择排序 选择排序方法有两种,直接选择排序和堆排序。直接选择排序简单直观,但是性能较差;堆排序较为高效,但是实现起来较为复杂。
1.1.1 直接选择排序 直接选择排序思想:程序遍历n个数,然后比较出最大的一个与最后一个数进行交换,最大值确定好了;接下来遍历n-1,找个这n-1个数中的最大值并且交换位置,直至n=0位置。 该排序方法的数据交换次数是,但是比较次数较多。总的时间效率是。空间效率是,并且算法不稳定。
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 package sort;import java.util.*;public class SelectSort { public static void selectSort (DataWrap[] data) { System.out.println("开始排序" ); int arrayLength = data.length; for (int i = 0 ; i < arrayLength - 1 ; i++ ) { int minIndex = i ; for (int j = i + 1 ; j < arrayLength ; j++ ) { if (data[minIndex].compareTo(data[j]) > 0 ) { minIndex = j; } } if (minIndex != i) { DataWrap tmp = data[i]; data[i] = data[minIndex]; data[minIndex] = tmp; } System.out.println(java.util.Arrays.toString(data)); } } public static void main (String[] args) { DataWrap[] data = { new DataWrap(21 , "" ), new DataWrap(30 , "" ), new DataWrap(49 , "" ), new DataWrap(30 , "*" ), new DataWrap(16 , "" ), new DataWrap(9 , "" ) }; System.out.println("排序之前:\n" + java.util.Arrays.toString(data)); selectSort(data); System.out.println("排序之后:\n" + java.util.Arrays.toString(data)); } }
1.1.2 堆排序 堆排序的思路:将数据建立成最大(小)堆,将根节点与最后一个节点交换;重复上面的过程。 1)堆树是一颗完全二叉树; 2)堆树中某个节点的值总是不大于或不小于其孩子节点的值; 3)堆树中每个节点的子树都是堆树。 当父节点的键值总是大于或等于任何一个子节点的键值时为最大堆。 当父节点的键值总是小于或等于任何一个子节点的键值时为最小堆。如下图所示,左边为最大堆,右边为最小堆。 引用:https://www.cnblogs.com/zf-blog/p/9010977.html 堆排序是选择算法的改进,可以减少选择排序中的比较次数,进而减少排序时间。对于堆排序来说,有n个数据,需要进行n-1次建堆,每次建堆本身耗时为,所以其时间效率为,堆排序是不稳定的。
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 59 60 61 62 63 64 65 66 67 package sort;public class HeapSort { public static void heapSort (DataWrap[] data) { System.out.println("开始排序" ); int arrayLength=data.length; for (int i=0 ;i<arrayLength-1 ;i++) { buildMaxdHeap(data,arrayLength-1 -i); swap(data,0 ,arrayLength-1 -i); System.out.println(java.util.Arrays.toString(data)); } } private static void swap (DataWrap[] data, int i, int j) { DataWrap tmp=data[i]; data[i]=data[j]; data[j]=tmp; } private static void buildMaxdHeap (DataWrap[] 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) { biggerIndex++; } if ((data[k].compareTo(data[biggerIndex])<0 )) { swap(data,k,biggerIndex); k=biggerIndex; }else { break ; } } } } public static void main (String[] args) { DataWrap[] data = { new DataWrap(21 , "" ), new DataWrap(30 , "" ), new DataWrap(49 , "" ), new DataWrap(30 , "*" ), new DataWrap(21 , "*" ), new DataWrap(16 , "" ), new DataWrap(9 , "" ) }; System.out.println("排序之前:\n" + java.util.Arrays.toString(data)); heapSort(data); System.out.println("排序之后:\n" + java.util.Arrays.toString(data)); } }
1.2 交换排序 交换排序的主体操作是对数组中的数据不断的进行交换操作。交换排序主要有冒泡排序和快速排序。
1.2.1 冒泡排序 冒泡排序思路:类似于鱼吐泡泡,一个接着一个,如果靠近鱼的泡泡比远离鱼的泡泡大,则两个泡泡就会交换。一次执行,就成了一串有序的泡泡。 时间效率:;空间效率:;算法是有序的;
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 package sort;public class BubbleSort { public static void bubbleSort (DataWrap[] data) { System.out.println("开始排序" ); int arrayLength=data.length; for (int i=0 ;i<arrayLength-1 ;i++) { for (int j=0 ;j<arrayLength-1 -i;j++) { if (data[j].compareTo(data[j+1 ])>0 ) { DataWrap tmp=data[j+1 ]; data[j+1 ]=data[j]; data[j]=tmp; } } System.out.println(java.util.Arrays.toString(data)); } } public static void main (String[] args) { DataWrap[] data = { new DataWrap(9 , "" ), new DataWrap(16 , "" ), new DataWrap(21 , "*" ), new DataWrap(23 , "" ), new DataWrap(30 , "" ), new DataWrap(49 , "" ), new DataWrap(21 , "" ), new DataWrap(30 , "*" ) }; System.out.println("排序之前:\n" + java.util.Arrays.toString(data)); bubbleSort(data); System.out.println("排序之后:\n" + java.util.Arrays.toString(data)); } }
1.2.2 快速排序 快速排序的思路:如列队一样,先选择一个士兵为基准,比该士兵高则站在其后面,比该士兵矮则站在其前面,这样大致将队伍分为了两个子列。然后在这两个子进行递归。 空间效率:,算法并不稳定。
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 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 package sort;import java.util.*;public class QuickSort { private static void swap (DataWrap[] data, int i, int j) { DataWrap tmp; tmp = data[i]; data[i] = data[j]; data[j] = tmp; } private static void subSort (DataWrap[] data , int start , int end) { if (start < end) { DataWrap base = data[start]; int i = start; int j = end + 1 ; while (true ) { while (i < end && data[++i].compareTo(base) <= 0 ); while (j > start && data[--j].compareTo(base) >= 0 ); if (i < j) { swap(data , i , j); } else { break ; } } swap(data , start , j); subSort(data , start , j - 1 ); subSort(data , j + 1 , end); } } public static void quickSort (DataWrap[] data) { subSort(data , 0 , data.length - 1 ); } public static void main (String[] args) { DataWrap[] data = { new DataWrap(9 , "" ), new DataWrap(-16 , "" ), new DataWrap(21 , "*" ), new DataWrap(23 , "" ), new DataWrap(-30 , "" ), new DataWrap(-49 , "" ), new DataWrap(21 , "" ), new DataWrap(30 , "*" ), new DataWrap(13 , "*" ) }; System.out.println("排序之前:\n" + java.util.Arrays.toString(data)); quickSort(data); System.out.println("排序之后:\n" + java.util.Arrays.toString(data)); } }
1.3 插入排序 插入排序主要分为直接插入排序、Shell排序和折半排序。
1.3.1 直接插入排序 直接插入排序思路:类似于把一堆杂乱的且大小不一的碗按从大到小(从小到大不符合实际)排序。我可以先拿出一个碗,然后在拿出碗与之比较;这两个碗排好序后,再拿出一个碗进行比较,插在其合适的顺序上,以此方式直至最后一个碗位置。 最坏情况的时间复杂度:;空间复杂度:;该算法是稳定的。
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 package sort;public class insertSort { public static void insertSort (DataWrap[] data) { System.out.println("开始排序" ); int arrayLenght=data.length; for (int i=1 ;i<arrayLenght;i++) { DataWrap tmp=data[i]; if (data[i].compareTo(data[i-1 ])<0 ){ int j=i-1 ; for (;j>=0 &&data[j].compareTo(tmp)>0 ;j--) { data[j+1 ]=data[j]; } data[j+1 ]=tmp; } System.out.println(java.util.Arrays.toString(data)); } } public static void main (String[] args) { DataWrap[] data = { new DataWrap(9 , "" ), new DataWrap(-16 , "" ), new DataWrap(21 , "*" ), new DataWrap(23 , "" ), new DataWrap(-30 , "" ), new DataWrap(-49 , "" ), new DataWrap(21 , "" ), new DataWrap(30 , "*" ), new DataWrap(13 , "*" ) }; System.out.println("排序之前:\n" + java.util.Arrays.toString(data)); insertSort(data); System.out.println("排序之后:\n" + java.util.Arrays.toString(data)); } }
1.3.2 折半插入排序 思路:与二分法有点相似。因为之前的数据是排好序的,因此为了减少比较次数,可以选择之前数据的中点与要插入的数据进行比较。我们拿到一个碗,把它插在已经排好的碗中时,可以先看中间的碗,如果中间的碗比插入的碗大,在进行二分即可。 算法可能不稳定;
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 59 60 package sort;public class BinaryInsertSort { public static void binaryInsertSort (DataWrap[] data) { System.out.println("开始排序:\n" ); int arrayLength = data.length; for (int i = 1 ; i < arrayLength ; i++) { DataWrap tmp = data[i]; int low = 0 ; int high = i - 1 ; while (low <= high) { int mid = (low + high) / 2 ; if (tmp.compareTo(data[mid]) > 0 ) { low = mid + 1 ; } else { high = mid - 1 ; } } for (int j = i ; j > low ; j--) { data[j] = data[j - 1 ]; } data[low] = tmp; System.out.println(java.util.Arrays.toString(data)); } } public static void main (String[] args) { DataWrap[] data = { new DataWrap(9 , "" ), new DataWrap(-16 , "" ), new DataWrap(21 , "*" ), new DataWrap(23 , "" ), new DataWrap(-30 , "" ), new DataWrap(-49 , "" ), new DataWrap(21 , "" ), new DataWrap(30 , "*" ), new DataWrap(30 , "" ) }; System.out.println("排序之前:\n" + java.util.Arrays.toString(data)); binaryInsertSort(data); System.out.println("排序之后:\n" + java.util.Arrays.toString(data)); } }
1.3.3 希尔排序 Shell排序方法思路:以一个较为合适的步长h,让数据中相差为h的步数进行排序;让后将步长改为h/2,在进行排序;递归下去,直至h=1。(当h=1是,可以认为此时的希尔排序算法就是直接插入排序算法)。对于直接插入算法来说,如果原始数据大部分是有序的,数据的移动操作就会较少。利用希尔排序算法就是把原始数据做到基本有序,有效的减少数据移动的操作。
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 class ShellSort { public static void shellSort (DataWrap[] data) { System.out.println("开始排序:" ); int arrayLength = data.length; int h = 1 ; while (h <= arrayLength / 3 ) { h = h * 3 + 1 ; } while (h > 0 ) { System.out.println("===h的值:" + h + "===" ); for (int i = h ; i < arrayLength ; i++ ) { DataWrap tmp = data[i]; if (data[i].compareTo(data[i - h]) < 0 ) { int j = i - h; for ( ; j >= 0 && data[j].compareTo(tmp) > 0 ; j-=h) { data[j + h] = data[j]; } data[j + h] = tmp; } System.out.println(java.util.Arrays.toString(data)); } h = (h - 1 ) / 3 ; } } public static void main (String[] args) { DataWrap[] data = { new DataWrap(9 , "" ), new DataWrap(-16 , "" ), new DataWrap(21 , "*" ), new DataWrap(23 , "" ), new DataWrap(-30 , "" ), new DataWrap(-49 , "" ), new DataWrap(21 , "" ), new DataWrap(30 , "*" ), new DataWrap(30 , "" ), }; System.out.println("排序之前:\n" + java.util.Arrays.toString(data)); shellSort(data); System.out.println("排序之后:\n" + java.util.Arrays.toString(data)); } }
1.4 归并排序 归并排序基本思想:就是将两个有序的序列合成一个新的有序序列。其时间效率为,需要一个与原始序列同样大的辅助序列,因此空间效率较差。算法是稳定的。
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 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 class DataWrap implements Comparable <DataWrap > { int data; String flag; public DataWrap (int data, String flag) { this .data = data; this .flag = flag; } public String toString () { return data + flag; } public int compareTo (DataWrap dw) { return this .data > dw.data ? 1 : (this .data == dw.data ? 0 : -1 ); } } public class MergeSort { public static void mergeSort (DataWrap[] data) { sort(data , 0 , data.length - 1 ); } private static void sort (DataWrap[] data , int left, int right) { if (left < right) { int center = (left + right) / 2 ; sort(data, left, center); sort(data, center + 1 , right); merge(data, left, center, right); } } private static void merge (DataWrap[] data , int left, int center, int right) { DataWrap[] tmpArr = new DataWrap[data.length]; int mid = center + 1 ; int third = left; int tmp = left; while (left <= center && mid <= right) { if (data[left].compareTo(data[mid]) <= 0 ) { tmpArr[third++] = data[left++]; } else { tmpArr[third++] = data[mid++]; } } while (mid <= right) { tmpArr[third++] = data[mid++]; } while (left <= center) { tmpArr[third++] = data[left++]; } while (tmp <= right) { data[tmp] = tmpArr[tmp++]; } } public static void main (String[] args) { DataWrap[] data = { new DataWrap(9 , "" ), new DataWrap(-16 , "" ), new DataWrap(21 , "*" ), new DataWrap(23 , "" ), new DataWrap(-30 , "" ), new DataWrap(-49 , "" ), new DataWrap(21 , "" ), new DataWrap(30 , "*" ), new DataWrap(30 , "" ) }; System.out.println("排序之前:\n" + java.util.Arrays.toString(data)); mergeSort(data); System.out.println("排序之后:\n" + java.util.Arrays.toString(data)); } }
https://www.cnblogs.com/tianliang94/p/10458888.html