不具有稳定性的排序:选择排序、快速排序、堆排序java
具有稳定性的排序:冒泡排序、插入排序、归并排序(nlogn)api
每次遍历找到数组中最小的元素的索引,依次交换。数组
public int[] sortArray (int[] nums) { for(int i=0; i<nums.length; i++) { int minIndex = i; for(int j=i+1; j<nums.length; j++) { minIndex = nums[j] < nums[minIndex] ? j : minIndex; } swap(nums, i, minIndex); } return nums; }
基本思路:ui
low 指针找到大于 pivot 的元素,hight 指针找到小于 pivot 的元素,而后两个元素交换位置,最后再将基准数归位。spa
public void quickSort (int[] nums, int low, int high) { if(low < high) { int index = partition(nums, low, high); quickSort(nums, low, index-1); quickSort(nums, index+1, high); } } public int partition(int[] nums, int low, int high) { int pivot = nums[low]; while(low < high) { while(low<high && nums[high] >= pivot) { high--; } nums[low] = nums[high]; while(low<high && nums[low] <= pivot) { low++; } nums[high] = nums[low]; } nums[low] = pivot; return low; }
其实这种方法,算是对上面方法的挖坑填坑步骤进行合并,low 指针找到大于 pivot 的元素,hight 指针找到小于 pivot 的元素,而后两个元素交换位置,最后再将基准数归位。指针
public void quickSort (int[] nums, int low, int high) { if(low < high) { int index = partition(nums, low, high); quickSort(nums, low, index-1); quickSort(nums, index+1, high); } } public int partition(int[] nums, int low, int high) { int pivot = nums[low]; int start = low; //记录low指针 while(low < high) { while(low < high && nums[high] >= pivot) high--; while(low < high && nums[low] <= pivot) low++; if(low >= high) { break; } swap(nums, low, high); } //基准值归位 swap(nums, start, low); return low; } public void swap(int[] nums, int i, int j) { if(i == j) return; nums[i] = nums[i] ^ nums[j]; nums[j] = nums[i] ^ nums[j]; nums[i] = nums[i] ^ nums[j]; }
两两比较相邻记录的关键字,若是是反序则交换,直到没有反序为止。code
public int[] sortArray(int[] nums) { for(int i=0; i<nums.length; i++) { for(int j=0; j<nums.length-i-1; j++) { if(nums[j] > nums[j+1]) { swap(nums, j, j+1); } } } return nums; } private void swap(int[] arr, int i, int j) { int temp = arr[i]; arr[i] = arr[j]; arr[j] = temp; }
冒泡排序能够用 标识flag 改进,若是交换则标识位发生变化,若是标识为没有变化,说明已经排序好了!排序
不断地与前面的数字比较,若是前面的数字比它大,它就和前面的数字交换位置。递归
public int[] sortArray(int[] nums) { for(int i=1; i<nums.length; i++) { int j = i; //记录当前数字下标 //当前数字比前一个数字小,则交换 while(j >= 1 && nums[j] < nums[j-1]) { swap(nums, j, j-1); j--; //继续向前一个元素比较 } } return nums; } public void swap(int[] nums, int i, int j) { int temp = nums[i]; nums[i] = nums[j]; nums[j] = temp; }
public int[] sortArray (int[] nums) { int[] temp = new int[nums.length]; mergeSort(nums, 0, nums.length-1, temp); return nums; } public void mergeSort(int[] nums, int low, int high, int[] temp) { int mid = (low + high) / 2; if(low < high) { //对左右进行拆分 mergeSort(nums, low, mid, temp); mergeSort(nums, mid+1, high, temp); //合并 merg(nums, low, high, mid, temp); } } public void merg(int[] nums, int low, int high, int mid, int[] temp) { int index = 0; int i = low; //左边序列起始索引 int j = mid + 1; //右边序列起始索引 while(i <= mid && j <= high) { if(nums[i] <= nums[j]) { //这里最好用 <= temp[index++] = nums[i++]; } else { temp[index++] = nums[j++]; } } //若左边序列还有剩余 while(i <= mid) { temp[index++] = nums[i++]; } //若右边序列还有剩余 while(j <= high) { temp[index++] = nums[j++]; } //把temp数组的赋值给原数组nums for(int t=0; t<index; t++) { nums[low + t] = temp[t]; } }
时间复杂度为:O(NlogN)
索引
额外空间复杂度为:O(N)
由于堆是彻底二叉树,因此咱们彻底能够用数组存储。将根节点的下标视为 0,则彻底二叉树有以下性质:
2i + 1
2i + 2
n/2 - 1
构建大顶堆:将整个数列的初始状态视做一棵彻底二叉树,自底向上调整树的结构,使其知足大顶堆的要求。
变量 heapSize 用来记录还剩下多少个数字没有排序完成,每当交换了一个堆顶的数字,heapSize 就会减 1。在 maxHeapify 方法中,使用 heapSize 来限制剩下的选手,不要和已经躺在数组最后,当过冠军的人比较,省得被暴揍。
public int[] sortArray(int[] nums) { //构建初始大顶堆 buildMaxHeap(nums); for(int i=nums.length - 1; i >= 0; i--) { swap(nums, 0, i); //将最大值放到数组的最后 maxHeapify(nums, 0, i); //调整剩余数组,使其知足大顶堆 } return nums; } public void buildMaxHeap(int[] nums) { // 从最后一个非叶子结点开始调整大顶堆,最后一个非叶子结点的下标就是 arr.length / 2-1 for(int i = nums.length / 2 - 1; i>=0; i--) { maxHeapify(nums, i, nums.length); } } //调整大顶堆(第三个参数表示剩余未排序的数字的数量,也就是剩余堆的大小) public void maxHeapify(int[] nums, int i, int heapSize) { int l = 2 * i + 1; // 左子结点下标 int r = l + 1; // 右子结点下标 int largest = i; //记录根结点和两个儿子之间的最大值 if(l < heapSize && nums[l] > nums[largest]) largest = l; if(r < heapSize && nums[r] > nums[largest]) largest = r; //若是有子结点大于根结点,则交换,并用 largest 去再次调整大顶堆。 if(largest != i) { swap(nums, i, largest); maxHeapify(nums, largest, heapSize); } } public void swap(int[] nums, int i, int j) { int temp = nums[i]; nums[i] = nums[j]; nums[j] = temp; }