快速排序 快速排序的思想是快速排序,通过首尾两个指针进行扫描
先让val=arr[0] 尾指针先开始移动,如果所指元素大于val, 则指针往前移动,当arr[i] < val的时候, 并且arr[0] = arr[i],尾指针停止移动 首指针开始移动, 当所指元素小于val的时候,指针后移,当arr[i] > val 的时候,让arr[尾指针位置] = arr[i] 终止条件: 尾指针的索引小于或者等于首指针
这样一轮过后,就可以确定该元素在数组中的位置,通过迭代的方法,来将基准数归位。
假设现在有这样一个数组
取出int val = arr[0] = 3, 首先,尾指针开始移动,直到找到arr[i]=1 < val,这时尾指针停止移动,并且把这个值赋给首指针指向的空间。
此时首指针开始移动,当arr[i] > val 的时候,将此时的值赋给尾指针所指向的位置。
然后尾指针开始移动,直到low >= high ,则结束,此时首尾指针重合,所指向的位置就是val排序后的位置。
大致就是这个过程,然后通过递归的方式,找到数的位置就可以了。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 public void quickSort (int [] arr, int low, int high) { if (low < high) { int pos = findPos(arr, low, high); quickSort(arr, low, pos-1 ); quickSort(arr, pos+1 , high); } } public int fingPos (int [] arr, low, high) { int val = arr[low]; while (low < high) { while (low < high && arr[high] >= val) high --; arr[ow] = arr[high]; while (low < high && arr[low] <= val) low ++; arr[high] = arr[low]; } arr[low] = val; return low; }
快排的时间复杂度为O(nlogn),并且不稳定。
基数排序 基数排序是通过空间来换时间的排序,需要更多的内存空间。基数排序需要10个一维数组(0123456789)。
首先,取出数组元素中所有元素的个位数,根据个位数字,将数组元素,放入到对应的一维数组中,比如有一个元素是98,其个位数字是8,那么就将98放入到第九个(即编号为8)的数组中。
放完所有元素之后,在按照顺序,从十个二维数组中取出来,组成新的数组,然后在比较十位,如果没有十位数字的元素则为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 public void radixSort (int [] nums) { int [][] buckets = new int [10 ][nums.length]; int [] bucketCount = new int [10 ]; int max = nums[0 ]; for (int i = 1 ; i < nums.length; i++) { if (max < nums[i]) { max = nums[i]; } } int maxLen = (max + "" ).length(); for (int i = 0 , n = 1 ; i < maxLen; i++, n *= 10 ) { for (int j = 0 ; j < nums.length; j++) { int digit = nums[j] / n % 10 ; buckets[digit][bucketCount[digit]++] = nums[j]; } int index = 0 ; for (int k = 0 ; k < bucketCount.length; k++) { if (bucketCount[k] > 0 ) { for (int h = 0 ; h < bucketCount[k]; h++) { nums[index++] = buckets[k][h]; buckets[k][h] = 0 ; } } bucketCount[k] = 0 ; } } }
基数排序的时间复杂度为O(logRB),稳定。
归并排序 归并排序,先将数组进行拆分,拆分成一个一个元素,将每个元素当做一个数组。然后在从最底层,进行合并,将两个数组合并成一个新的数组,最后变成有序数组。
先看下面的数组,拆分的过程
然后在进行合并,如下每一个都代表一个数组
简单来说,就是先对数组进行拆分,拆分到最后每个元素都是一个数组,然后在将数组进行合并,放入一个新的数组中。
代码如下
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 public void mergeSort (int [] nums, int left, int right, int [] tmp) { if (left < right) { int mid = left + (right - left) / 2 ; mergeSort(nums, left, mid, tmp); mergeSort(nums, mid + 1 , right, tmp); merge(nums, left, mid, right, tmp); } } private void merge (int [] nums, int left, int mid, int right, int [] tmp) { for (int i = left; i <= right; i++) { tmp[i] = nums[i]; } int i = left; int j = mid + 1 ; for (int k = left; k <= right; k++) { if (i == mid + 1 ) { nums[k] = tmp[j]; j++; } else if (j == right + 1 ) { nums[k] = tmp[i]; i++; } else if (tmp[i] <= tmp[j]) { nums[k] = tmp[i]; i++; } else { nums[k] = tmp[j]; j++; } } }
归并排序算法每次将序列折半分组,共需要logn轮,因此归并排序算法的时间复杂度是O(nlogn)。并且是稳定的。
堆排序 堆排序是将一个无序的数组构建成一个堆,如果升序则构建成大顶堆、降序则构建小顶堆。
大顶堆: 从最后一个非叶子节点开始,该节点的值大于或等于其左右孩子节点的值,小顶堆则相反。
构建好大顶堆之后,将最末尾元素和根节点交换,这样末尾元素就是最大值,然后再重新调整堆,然后在交换根节点与末尾元素。如此反复。
我们举个例子,现在有一个数组如下
先构建大顶堆,最后一个非叶子节点arr[1] = 7, 比较左右孩子节点,发现右孩子值最大,则交换位置
接着找到倒数第二个非叶子节点,arr[0] = 5,左孩子比它大,所以交换位置,如下:
然后继续调整堆
最后就得到了一个大顶堆。
得到大顶堆后,根节点为数组最大值,这时,把根节点与最末元素进行交换,则最末元素是最大值。然后再进行调整,按照数组的下标,对于第k个节点,它的左孩子是2k+1、它的右孩子是2k+2。将9和5交换位置,就确定了最大值
然后对剩下的元素,再进行调整,让他成一个大顶堆
再次进行根节点和末尾元素进行交换。即7和1交换
剩下的元素,再进行大顶堆的调整
然后再进行交换,即5和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 51 52 53 54 public void heapSort (int [] arr) { for (int i=arr.length/2 - 1 ; i >=0 ; i--) { adjustHeap(arr, i, arr.length) } for (int j=arr.length-1 ; j>=0 ; j--) { swap(arr, 0 , j); adjustHeap(arr, 0 , j); } } public void adjustHeap (int [] arr, int i, int length) { int val = arr[i]; for (int k = 2 *i+1 ; k<length; k = 2 *k+1 ) { if (k+1 < length && arr[k] < arr[k+1 ]) { k ++; } if (arr[k] > val) { arr[i] = arr[k]; i = k; } else { break ; } } arr[i] = val; } public void swap (int [] arr, int a, int b) { int temp = 0 ; temp = arr[a]; arr[a] = arr[b]; arr[b] = temp; }
堆排序的时间复杂度为O(nlogn), 是一种选择排序,并且不稳定。