基本排序算法
该部分是对算法(四)简单排序的总结。
算法1、简单选择排序
基本思想:
是一种最简单的排序算法,首先,找到数组中最小的那个元素,然后,将它和数组中的第一个元素交换位置。再次,在剩下的元素中找到最小的元素,将它与数组的第二个元素交换位置。如此往复,直到将整个数组排序。
算法特点:
- 对于长度为N的数组,选择排序需要大约N2/2次比较和N次交换。
- 运行时间和输入无关,这也导致了无论输入的数据是有序还是无序,执行的时间将是一样长。
- 数据移动是最少的。
- 时间复杂度O(N2),空间复杂度O(1),不稳定。如:(5,4,5,2)排序后两个5的相对位置发生的变化。
1 package basic.sort; 2 /** 3 * 选择排序 4 * 5 * Created by Evan on 2016-8-18. 6 */ 7 public class SelectionSort { 8 public static void selectSort(int[] a) { 9 int i; 10 int j; 11 int temp = 0; 12 int flag = 0; 13 int n = a.length; 14 for (i = 0; i < n; i++) { 15 temp = a[i]; 16 flag = i; 17 for (j = i + 1; j < n; j++) { 18 if (a[j] < temp) { 19 temp = a[j]; 20 flag = j; 21 } 22 23 } 24 System.out.println(j); 25 if (flag != i) { 26 a[flag] = a[i]; 27 a[i] = temp; 28 } 29 } 30 31 } 32 public static void main(String[] args) { 33 int i = 0; 34 int a[] = {5,4,7,8,9,9,10,2,3,1}; 35 selectSort(a); 36 for(i = 0; i< a.length;i++){ 37 System.out.print(a[i] + " "); 38 } 39 } 40 }
算法2、插入排序
基本思想:
将每一张牌插入到其他已经有序的牌中的适当位置。将其余元素在插入前都向右移动一位。
算法特点:
平均插入排序需要N2/4比较和N2/4交换,最坏情况下N2/2比较和N2/2交换,最好情况下需要N-1次比较和0次交换。适合对部分有序的数组排序。
时间复杂度最好为O(N),平均和最坏为O(N2),空间复杂度为O(1),稳定排序
1 package basic.sort; 2 3 import java.util.Arrays; 4 5 /** 6 * 插入排序 7 * 8 * Created by Evan on 2016-8-18. 9 */ 10 public class InsertSort { 11 public static void insertSort(int[] a) { 12 if (a != null) { 13 for (int i = 1; i < a.length; i++) { 14 int temp = a[i]; 15 int j = i; 16 17 while (j >= 1&&a[j - 1] > temp) { 18 a[j] = a[j - 1]; 19 j--; 20 } 21 22 a[j] = temp; 23 } 24 } 25 } 26 public static void main(String []args){ 27 int a[] = {5,4,7,8,9,10,9,2,3,1}; 28 insertSort(a); 29 System.out.println(Arrays.toString(a)); 30 } 31 }
两者比较:对于随机排序的无重复主键的数组,插入排序和选择排序的运行时间是平方级别的,两者之比应该是一个较小的常数。
算法3、希尔排序
基本思想:
使数组中任意间隔为h的元素都是有序的。
算法特点:
在插入排序的基础上,将移动元素的距离有1改为h,希尔排序高效的原因是它权衡了子数组的规模和有序性。排序之初,各个子数组都很短,排序之后,子数组都是部分有序的。子数组部分有序的程度取决于递增序列的选择。时间复杂度达不到平方级。空间复杂度为O(1),不稳定。
1 package basic.sort; 2 3 import java.util.Arrays; 4 /** 5 * 希尔排序 6 * 按升序排列 7 * Created by Evan on 2016-8-18. 8 */ 9 public class ShellSort { 10 public static void sort(int a[]){ 11 int N = a.length; 12 int h = 1; 13 while(h < N/3) 14 h = h * 3 + 1; //1,4,13,40,121,.... 15 while(h >= 1){ 16 for(int i = h; i < N; i++){ 17 //将a[i]插入到a[i-h],a[i-2*h],a[i-3*h].....之中 18 for(int j = i;j >= h && a[j] < a[j - h]; j -= h){ 19 int temp = a[j]; 20 a[j] = a[j - h]; 21 a[j - h] = temp; 22 } 23 } 24 h = h / 3; 25 } 26 } 27 public static void main(String []args) { 28 int[] nums = {2, 7, 8, 3, 1, 6, 9, 4, 5, 4}; 29 ShellSort.sort(nums); 30 System.out.println(Arrays.toString(nums)); 31 } 32 }
算法4、归并排序
基本思想:
先递归的将它分成两半分别排序,然后将结果归并起来。
算法特点:
时间复杂度最好、最坏和平均复杂度为O(nlogn),空间复杂度为O(n),稳定排序。没有任何基于比较的算法能够保证使用少于lg(N!) ~ NlgN次比较将长度为N的数组排序。
1 package basic.sort; 2 /** 3 * 归并排序 4 * 5 * Created by Evan on 2016-8-19. 6 */ 7 public class MergeSort { 8 public static void Merge(int nums[], int low, int mid, int high) { 9 int[] temp = new int[high - low + 1]; 10 int i = low;// 左指针 11 int j = mid + 1;// 右指针 12 int k = 0; 13 14 // 把较小的数先移到新数组中 15 while (i <= mid && j <= high) { 16 if (nums[i] < nums[j]) { 17 temp[k++] = nums[i++]; 18 } else { 19 temp[k++] = nums[j++]; 20 } 21 } 22 23 // 把左边剩余的数移入数组 24 while (i <= mid) { 25 temp[k++] = nums[i++]; 26 } 27 28 // 把右边边剩余的数移入数组 29 while (j <= high) { 30 temp[k++] = nums[j++]; 31 } 32 33 // 把新数组中的数覆盖nums数组 34 for (int k2 = 0; k2 < temp.length; k2++) { 35 nums[k2 + low] = temp[k2]; 36 } 37 } 38 39 public static void MergeSort1(int a[], int l, int r) { 40 if (l < r) { 41 int mid = (l + r) / 2; 42 MergeSort1(a, l, mid); 43 MergeSort1(a, mid + 1, r); 44 Merge(a, l, mid, r); 45 } 46 } 47 48 public static void main(String[] args) { 49 int a[] = { 5, 4, 7, 8, 9, 5, 9, 2, 3, 1 }; 50 MergeSort1(a, 0, a.length - 1); 51 for (int i = 0; i < a.length; i++) { 52 System.out.print(a[i] + " "); 53 } 54 } 55 }
算法5、快速排序
基本思想:
将一个数组分层两个子数组,将两部分独立地排序,快速排序和归并排序是互补的:归并排序将数组分层两个子数组分别排序,并将有序的子数组归并以将整个数组排序。而快速排序将数组排序的方式则是当两个子数组都有序时整个数组也就自然有序了。
算法特点:
时间复杂度平均和最好为O(nlogn),最坏为O(N2),空间复杂度为O(1),不稳定排序。
1 package basic.sort; 2 /** 3 * 快速排序 4 */ 5 import java.util.Arrays; 6 7 public class QuickSort { 8 public static int[] sort(int[] nums, int low, int high) { 9 if (low < high) { 10 int mid = partition(nums, low, high); 11 //左边 12 sort(nums, low, mid - 1); 13 //右边 14 sort(nums, mid + 1, high); 15 } 16 return nums; 17 } 18 19 public static int partition(int[] nums, int low, int high) { 20 int key = nums[low];//基准数 21 int i = low;//左指针 22 int j = high;//右指针 23 24 if (low < high) { 25 while (i < j) { 26 //形象点可以理解为,右指针左移 27 while (i < j && nums[j] >= key) { 28 j--; 29 } 30 31 if (i < j) { 32 nums[i] = nums[j]; 33 i++; 34 } 35 36 //形象点可以理解为,左指针右移 37 while (i < j && nums[i] <= key) { 38 i++; 39 } 40 41 if (i < j) { 42 nums[j] = nums[i]; 43 j--; 44 } 45 } 46 47 //把key填入最后的位置,即基准数位 48 nums[i] = key; 49 } 50 return i; 51 } 52 53 public static void main(String[] args) { 54 int[] nums = {2, 7, 8, 3, 1, 6, 9, 0, 5, 4}; 55 56 QuickSort.sort(nums, 0, nums.length - 1); 57 System.out.println(Arrays.toString(nums)); 58 } 59 }
算法6、堆排序
基本思想:
通过建堆和调整堆的方式,将数组排序。
算法特点:
时间复杂度最好,平均和最坏都是O(nlogn),空间复杂度为O(1)不稳定。
1 package basic.sort; 2 3 import java.util.Arrays; 4 /** 5 * 堆排序 6 * 降序 7 * 8 * Created by Evan on 2016-8-19. 9 */ 10 public class HeapSort { 11 12 public static void MinHeapFixdown(int a[], int i, int n) { 13 int j, temp; 14 15 temp = a[i]; 16 j = 2 * i + 1; 17 while (j < n) { 18 if (j + 1 < n && a[j + 1] < a[j]) // 在左右孩子中找最小的 19 j++; 20 21 if (a[j] >= temp) 22 break; 23 24 a[i] = a[j]; // 把较小的子结点往上移动,替换它的父结点 25 i = j; 26 j = 2 * i + 1; 27 } 28 a[i] = temp; 29 } 30 31 public static void MinheapsortTodescendarray(int a[], int n) { 32 for(int i = a.length / 2 - 1; i>= 0; i--){ 33 MinHeapFixdown(a,i,a.length); 34 } 35 for (int i = n - 1; i >= 1; i--) { 36 int temp = a[0]; 37 a[0] = a[i]; 38 a[i] = temp; 39 MinHeapFixdown(a, 0, i); 40 } 41 } 42 43 public static void main(String[] args) { 44 int[] nums = { 2, 7, 8, 3, 1, 6, 9, 4, 5, 4 }; 45 46 HeapSort.MinheapsortTodescendarray(nums, nums.length); 47 System.out.println(Arrays.toString(nums)); 48 } 49 }
算法7、冒泡排序
基本思想:
两两比较,将较小的向上调整,较大的向下交换,较小的数就好比气泡一样向上浮动。
算法特点:
时间复杂度最好为O(n),平均和最坏为O(N2),空间复杂度O(1),稳定排序。
1 package basic.sort; 2 3 import java.util.Arrays; 4 /** 5 * 冒泡排序 6 * 这里提供两个版本,本质是一样的,注释部分是每次将未排序中最大的数排到最终位置; 7 * 第二种,是将未排序中最小的数排到最终位置。 8 * Created by Evan on 2016-8-18. 9 */ 10 public class BubbleSort { 11 public static void bubbleSort(int[] a) { 12 int i; 13 int j; 14 int len = a.length; 15 int temp; 16 /*for (i = 0; i < len; i++) { 17 for (j = 0; j + 1 < len - i; j++) { 18 if (a[j + 1] < a[j]) { 19 temp = a[j]; 20 a[j] = a[j + 1]; 21 a[j + 1] = temp; 22 } 23 } 24 //System.out.println(i+1 + ": "+Arrays.toString(a)); 25 }*/ 26 for (i = 0; i < len; i++) { 27 for (j = len - 1; j > i; j--) { 28 if (a[j - 1] > a[j]) { 29 temp = a[j]; 30 a[j] = a[j - 1]; 31 a[j - 1] = temp; 32 } 33 } 34 //System.out.println(i+1 + ": "+Arrays.toString(a)); 35 } 36 } 37 38 public static void main(String[] args) { 39 int a[] = { 5, 4, 7, 8, 9, 5, 9, 2, 3, 1 }; 40 bubbleSort(a); 41 System.out.println(Arrays.toString(a)); 42 } 43 }