题目链接:https://leetcode-cn.com/problems/sort-an-array/submissions/
这是一道好题目,可以用来练习手撕各种排序算法,别直接调用api错过了这道好题哦!
目录
一、插入排序
直接插入排序:超时
折半插入排序:AC
希尔排序:AC
二、交换排序
冒泡排序:AC
快速排序:AC
三、选择排序
选择排序:AC
堆排序:AC
四、归并排序
归并排序:AC
五、JavaScript 内部 API
直接调用API:AC
/** * @param {number[]} nums * @return {number[]} */ var sortArray = function (nums) { sort(nums); return nums; }; //插入排序 //稳定排序 //时间复杂度O(n2) function sort(arr) { //首先把数组当做第一个元素为有序的序列,然后将后面的元素依次插入到合适的位置 let i, j; for (i = 1; i < arr.length; i++) { if (arr[i] < arr[i - 1]) { let temp = arr[i]; //哨兵 for (j = i - 1; temp < arr[j]; j--) { arr[j+1] = arr[j]; //直接往后覆盖移动,数据已经被哨兵保存 } arr[j+1] = temp; } } }
/** * @param {number[]} nums * @return {number[]} */ var sortArray = function (nums) { sort(nums); return nums; }; //稳定排序,之后小于才会引起移动,等于不会引起移动 //时间复杂度O(n2) //折半插入排序 function sort(arr) { //先用折半查找的方式,找到待插入的位置,然后直接后移 let i, j, low, high, mid; for (i = 1; i < arr.length; i++) { let temp = arr[i] //哨兵暂存 low = 0; //默认i之前的所有元素已经是有序的 high = i - 1; while (low <= high) { mid = ((high - low) > 2) + low; if (arr[mid] > temp) { high = mid - 1; } else { low = mid + 1; } } for(j = i-1;j >=high+1;j--){ arr[j+1] = arr[j]; } arr[high+1] = temp; } }
/** * @param {number[]} nums * @return {number[]} */ var sortArray = function (nums) { shellSort(nums); return nums; }; //不稳定排序 //时间复杂度O(n2) //希尔排序 function shellSort(arr) { let len = arr.length; let gap = Math.floor(len / 2), i for (gap; gap > 0; gap = Math.floor(gap / 2)) { for (i = gap; i < len; i++) { if (arr[i] < arr[i - gap]) { let temp = arr[i] for (j = i - gap; j >= 0 && temp < arr[j]; j -= gap) { arr[j + gap] = arr[j]; } arr[j + gap] = temp; } } } }
/** * @param {number[]} nums * @return {number[]} */ var sortArray = function (nums) { bubbleSort(nums); return nums; }; //稳定排序 //时间复杂度最好O(n) //冒泡排序 function bubbleSort(arr) { let flag; //表示本趟冒泡是否发生交换的标志 for (let i = 0; i < arr.length - 1; i++) { flag = false; for (let j = arr.length - 1; j > i; j--) { //i之前的所有元素都是排好序的 if (arr[j - 1] > arr[j]) { let temp = arr[j]; arr[j] = arr[j - 1] arr[j - 1] = temp flag = true; } } if (flag === false) { //本趟未发生交换,则说明已经有序,可以剪枝 return; } } }
/** * @param {number[]} nums * @return {number[]} */ var sortArray = function (nums) { let low = 0, high = nums.length - 1 quickSort(nums, low, high); return nums; }; //手撕快排 //时间复杂度最好O(ologn) //不稳定排序 //找到枢值的准确排序位置 function partition(arr, low, high) { let pivot = arr[low]; //默认第一个元素为枢轴值 while (low < high) { while (low < high && arr[high] >= pivot) --high; arr[low] = arr[high]; while (low < high && arr[low] <= pivot) ++low; arr[high] = arr[low]; } arr[low] = pivot; return low; } function quickSort(arr, low, high) { if (low < high) { let pivotPos = partition(arr, low, high); quickSort(arr, low, pivotPos - 1); quickSort(arr, pivotPos + 1, high); } } sortArray([0, 5, 2, 4, 3])
/** * @param {number[]} nums * @return {number[]} */ var sortArray = function (nums) { selectSort(nums); return nums; }; //不稳定排序 //时间复杂度O(n2) //选择排序 function selectSort(arr) { let min; for (let i = 0; i < arr.length - 1; i++) { //只需要比较n-1趟 min = i; for (let j = i + 1; j < arr.length; j++) { if(arr[j] < arr[min]) min = j; } if(min !== i){ let tmp = arr[min]; arr[min] = arr[i]; arr[i] = tmp; } } }
/** * @param {number[]} nums * @return {number[]} */ var sortArray = function (nums) { nums.unshift(-1); return HeapSort(nums); }; //不稳定排序 //时间复杂度最好O(nlog2n) //堆排序 /* * 堆是一个完全二叉树,满足任意一个非叶节点的值都不大于其左右孩子节点的值(小顶堆) * 不小于 大顶堆 * 思想:将无序序列调节成一个堆,然后从堆中选择堆顶元素的值,将这个值加入有序序列,无序序列减少一个值 * * 调节顺序:由下至上,由右至左 * */ function HeapSort(arr) { let len = arr.length - 1; let ans = [] BuildMinHeap(arr); //建立小顶堆 for (let i = len; i > 0; i--) { let tmp = arr[1]; arr[1] = arr[i]; arr[i] = tmp; ans.push(arr[i]); AdjustDown(arr, 1, i - 1); } return ans; } //建堆,反复调整 function BuildMinHeap(arr) { let len = arr.length - 1 for (let i = Math.floor(len / 2); i > 0; i--) { //Math.floor(len / 2) 第一个可能需要调整的非叶子节点 AdjustDown(arr, i, len) } } //调整一次,k为开始检查点 function AdjustDown(arr, k, len) { arr[0] = arr[k]; for (let i = 2 * k; i <= len; i *= 2) { //2 * k 为其左孩子 if (i < len && arr[i] > arr[i + 1]) i++; //找到左右孩子中值更大的那个 if (arr[0] <= arr[i]) { break //树顶已经最小 } else { arr[k] = arr[i]; k = i; } } arr[k] = arr[0]; }
/** * @param {number[]} nums * @return {number[]} */ var sortArray = function (nums) { mergeSort(nums, 0, nums.length - 1); return nums; }; //稳定排序 //时间复杂度最好O(nlog2n) //归并排序 function mergeSort(arr, low, high) { if (low < high) { //至少保证有2个元素,使其归并合一 let mid = Math.floor((low + high) / 2); mergeSort(arr, low, mid); //递归分组 mergeSort(arr, mid + 1, high); merge(arr, low, mid, high); //两两合并 } } function merge(arr, low, mid, high) { let tmpArr = [] let pos = low, i, j for (let k = low; k <= high; k++) { tmpArr[k] = arr[k] //元素复制,左右归并 } for (i = low, j = mid + 1; i <= mid && j <= high; pos++) { if (tmpArr[i] <= tmpArr[j]) { arr[pos] = tmpArr[i++] } else { arr[pos] = tmpArr[j++] } } while (i <= mid) arr[pos++] = tmpArr[i++]; while (j <= high) arr[pos++] = tmpArr[j++]; }
/** * @param {number[]} nums * @return {number[]} */ var sortArray = function(nums) { return nums.sort((a,b)=>a-b) };
除了直接插入排序超时,其他都可以执行,小伙伴们练手吧~