1、堆排序 1.1 堆的定义
1.2 堆排序的思路(大顶堆) (1)根据初始数组去构建初始堆 。
(2)每次交换第一个和最后一个元素,输出最后一个元素(最大值) ,然后把剩下元素重新调整为大顶堆,再进行交换第一个元素和最后一个元素,再调整大顶堆,重复执行,直到整个数组排序完成。
1.2.1 建堆的过程:
代码:
1 2 3 4 5 6 for (int i = arr.length/2 -1 ; i >=0 ; i--) { heapify(arr,i,arr.length - 1 ); }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 private void heapify (int [] arr, int i, int last_index) { int max = i; if ((2 *i+1 ) <= last_index && arr[2 *i+1 ] > arr[max]) { max = 2 *i+1 ; } if ((2 *i+2 ) <= last_index && arr[2 *i+2 ] > arr[max]) { max = 2 *i+2 ; } if (max != i) { swap(arr,i,max); heapify(arr,max,last_index); } return ; }
1.2.2 堆排序的过程:
代码: 1 2 3 4 5 6 7 for (int i = arr.length - 1 ; i > 0 ; i--) { swap(arr,i,0 ); heapify(arr,0 ,i - 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 public class HeapSort { public void heapSort (int [] arr) { for (int i = arr.length/2 -1 ; i >=0 ; i--) { heapify(arr,i,arr.length - 1 ); } for (int i = arr.length - 1 ; i > 0 ; i--) { swap(arr,i,0 ); heapify(arr,0 ,i - 1 ); } } private void heapify (int [] arr, int i, int last_index) { int max = i; if ((2 *i+1 ) <= last_index && arr[2 *i+1 ] > arr[max]) { max = 2 *i+1 ; } if ((2 *i+2 ) <= last_index && arr[2 *i+2 ] > arr[max]) { max = 2 *i+2 ; } if (max != i) { swap(arr,i,max); heapify(arr,max,last_index); } return ; } private void swap (int [] arr, int i, int j) { int tmp = arr[i]; arr[i] = arr[j]; arr[j] = tmp; } }
1.3 算法稳定性(不稳定) 在建立堆的调整步骤里,由于关键字相同的两个记录位置并不会被调换,所以建堆 的时候是稳定的 。但是,在堆顶与堆尾交换的时候两个相等 的记录在例中的相对位置 就可能发生改变,这就影响其稳定性 了。
1.4 时间复杂度 堆排序包括两个阶段,初始化建堆 和重建堆 。所以堆排序的时间复杂度由这两方面组成。 初始化建堆 的时间复杂度为O(n) ,排序重建堆的时间复杂度为O(nlogn) ,所以总 的时间复杂度为O(n+nlogn)=**O(nlogn)**。
2、冒泡排序 2.1 思路
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 public class Bubbling { public static void main (String[] args) { int [] arr = {67 ,42 ,88 ,16 ,25 ,3 }; for (int i = 0 ; i < arr.length - 1 ; i++) { for (int j = 0 ; j < arr.length - 1 - i; j++) { if (arr[j] > arr[j + 1 ]) { int tmp = arr[j]; arr[j] = arr[j + 1 ]; arr[j + 1 ] = tmp; } } } } }
2.2 算法稳定性 如果待排序的序列中存在两个或两个以上具有相同关键词的数据,排序后这些数据的相对次序保持不变,通俗地讲,就是两个相同的数的相对顺序不会发生改变,则该算法是稳定的;冒泡排序足稳定的 排序算法。
2.3 时间复杂度 对于n位的数列则有比较次数为(n-1) + (n-2)+ ..+ 1=n*(n- 1)/2.这就得到了最大的比较次数, n(n-1)/2 = (n^2 - n)/2,计算时间复杂度的时候,忽略常数项1/2,再忽略低阶项n ,得到冒泡排序的时间复杂度为0(n^2)
3、选择排序 选择排序: 通过一趟遍历,找到最小值的下标。 和下标为0的元素交换。 下一趟,从剩下的元素(排除下标0), 找到最小值的下标,然后和下标为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 public class selectSort { public static void main (String[] args) { int [] a = {35 ,22 ,17 ,41 ,72 ,29 ,10 }; for (int i = 0 ; i < a.length - 1 ; i++) { int min = a[i]; int index = i; for (int j = i + 1 ; j < a.length; j++) { if (a[j] < min) { min = a[j]; index = j; } } int temp = a[index]; a[index] = a[i]; a[i] = temp; } } }
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 public class quickSort { public static void main (String[] args) { int [] a = {23 ,-9 ,78 ,3 ,34 ,3 ,0 ,34 ,23 }; quickSort(a,0 ,a.length - 1 ); for (int i = 0 ; i < a.length; i++) { System.out.print(a[i] + " " ); } } static void quickSort (int [] arr, int left, int right) { if (left >= right) { return ; } int l = left; int r = right; while (l < r) { while (l < r && arr[r] >= arr[left]) r--; while (l < r && arr[l] <= arr[left]) l++; if (l == r) { int temp = arr[l]; arr[l] = arr[left]; arr[left] = temp; }else { int temp = arr[l]; arr[l] = arr[r]; arr[r] = temp; } } quickSort(arr,left,l - 1 ); quickSort(arr,l + 1 ,right); } }
2.2 算法稳定性 如果待排序的序列中存在两个或两个以上具有相同关键词的数据,排序后这些数据的相对次序保持不变,通俗地讲,就是两个相同的数的相对顺序不会发生改变,则该算法是稳定的;冒泡排序足不稳定的 排序算法。
2.3 时间复杂度
5、插入排序 5.1 思路 假设前面 n-1 (其中 n>=2 )个数已经是排好顺序的,现将第 n 个数插到前面已经排好的序列中,然后找到合适自己的位置,使得插入第n个数的这个序列也是排好顺序的。
代码:
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 class insertSort { public static void main (String[] args) { int [] a = {23 ,-9 ,78 ,3 ,34 ,3 ,0 ,34 ,23 }; insertSort(a); for (int i = 0 ; i < a.length; i++) { System.out.print(a[i] + " " ); } } static void insertSort (int [] arr) { for (int i = 1 ; i < arr.length; i++) { for (int j = i ; j > 0 ; j--) { if (arr[j] < arr[j - 1 ]) { int tmp = arr[j]; arr[j] = arr[j - 1 ]; arr[j - 1 ] = tmp; }else { break ; } } } } }
5.2 算法稳定性 如果待排序的序列中存在两个或两个以上具有相同关键词的数据,排序后这些数据的相对次序保持不变,通俗地讲,就是两个相同的数的相对顺序不会发生改变,则该算法是稳定的;冒泡排序足稳定的 排序算法。
5.3 时间复杂度 插入排序的平均时间复杂度也是 **O(n^2)**,空间复杂度为常数阶 **O(1)**,具体时间复杂度和数组的有序性也是有关联的。
插入排序中,当待排序数组是有序时,是最优的情况,只需当前数跟前一个数比较一下就可以了,这时一共需要比较 N-1 次,时间复杂度为 **O(N)**。最坏的情况是待排序数组是逆序的,此时需要比较次数最多,最坏的情况是 **O(n^2)**。