题目链接:https://leetcode-cn.com/problems/sort-an-array/submissions/
这是一道好题目,可以用来练习手撕各种排序算法,别直接调用api错过了这道好题哦!
目录
一、插入排序
(1)直接插入排序:超时
(2)折半插入排序:AC
(3)希尔排序:AC
二、交换排序
(1)冒泡排序:AC
(2)快速排序【递归】:AC
(3)快读排序【非递归】:AC
三、选择排序
(1)选择排序:AC
(2)堆排序:AC
四、归并排序
(1)归并排序:AC
五、JavaScript 内部 API
(1)直接调用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);
}
}
/**
* @param {number[]} nums
* @return {number[]}
*/
var sortArray = function (nums) {
let stack = []
quickSort(nums, stack);
return nums;
};
//手撕快排-非递归
function quickSort(arr, stack) {
let l = 0,r = arr.length-1;
stack.push(l);
stack.push(r);
while(stack.length !== 0){
let rr = stack.pop();
r = rr;
let ll = stack.pop();
l = ll;
let pivot = arr[ll];
if(ll < rr){
while(ll < rr){
while(ll < rr && arr[rr] >= pivot) rr--;
arr[ll] = arr[rr];
while(ll < rr && arr[ll] <= pivot) ll++;
arr[rr] = arr[ll];
}
arr[ll] = pivot;
stack.push(l);
stack.push(ll-1);
stack.push(ll+1);
stack.push(r);
}
}
}
/**
* @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)
};
除了直接插入排序超时,其他都可以执行,小伙伴们练手吧~