【算法】排序算法学习记录

40 篇文章 2 订阅
4 篇文章 0 订阅
本文记录了快速排序和归并排序的学习过程。快速排序通过选取pivot进行分区,实现平均时间复杂度为O(nlogn)。归并排序同样采用递归,时间复杂度相同,但空间复杂度为O(n)。文中提供了参考题目和作者的算法实现。
摘要由CSDN通过智能技术生成

前言

按照重点掌握程度列个表,其他的算法就先不用管了

算法程度要求时间复杂度空间复杂度稳定性
快速排序重点掌握O(nlogn)O(logn)不稳定
归并排序重点掌握O(nlogn)O(n)稳定
堆排序熟悉O(n2)O(1)不稳定
冒泡排序了解O(n2)O(1)稳定
选择排序了解O(n2)O(1)不稳定

快速排序

快排是必考的,思路如下,b站一个up讲得挺清晰的

  • 三个指针,left,right和pivot,每次pivot取一个值(假设都取数组首位),left、right都和pivot进行比较;
  • right > pivot , 就 right-- ,否则就让right位置的值移到pivot位置上,即小的都移到左边;
  • right操作完后,left进行同样操作
  • 左右指针相互进行,如果rigth指针的值一直大于pivot的值,那么指针就一直–,直到left >= right
  • 该轮排序结束,pivot的左边都比它小,右边都比它大,然后进行递归

时间复杂度:

  • 因为有递归,并且是每次二分的进行递归,所以算是logn
  • 每一次递归中,left都会和right相遇,所以是走遍了整个数组,所以是n
  • 总的加起来就是 nlogn

空间复杂度:

  • 因为有递归,所以跟递归相关,是 logn

参考题目

912. 排序数组

本人的快排做法

/**
 * @param {number[]} nums
 * @return {number[]}
 */
var sortArray = function (nums) {
    const quickSort = (nums, L, R)=>{
        if (L >= R) return
        let l = L
        let r = R
        let pivot = nums[l]
        while (l < r) {
            while (l < r && nums[r] >= pivot) {
                r--
            }
            if (l < r) {
                nums[l] = nums[r]
            }
            while (l < r && nums[l] <= pivot) {
                l++
            }
            if (l < r) {
                nums[r] = nums[l]
            }
            if (l >= r) {//这里其实可以放到while循环之外的,当时没想到
                nums[l] = pivot
            }
        }
        quickSort(nums,L,l-1)
        quickSort(nums,l+1,R)
    }
    quickSort(nums,0,nums.length-1)
    return nums
};

后来再看,不够简洁,性能不高,看了看大神的算法,如下

/**
 * @param {number[]} nums
 * @return {number[]}
 */
var sortArray = function (nums) {
    const swap = (arr, i, j) => {
        [arr[i], arr[j]] = [arr[j], arr[i]]
    }

    const _quickSort = (arr, left, right) => {
        if (left >= right) {
            return
        }
        let o = left
        let i = left, j = right
        while (left !== right) {
            // 先从右往左动
            while (arr[right] >= arr[o] && left < right) {
                right--
            }
            while (arr[left] <= arr[o] && left < right) {
                left++
            }
            if (left < right) {
                swap(arr, left, right)
            }
        }
        swap(arr, o, left)
        _quickSort(arr, i, left - 1)
        _quickSort(arr, left + 1, j)
    }
    _quickSort(nums, 0, nums.length - 1)
    return nums
};

但是,这个运算时间却更慢。。。

归并排序

也是利用递归,在每次递归里面,进行 left — mid 和 mid+1 — right 两段数组的比较(都从头开始比)
时间复杂度同样是 nlogn
但是空间复杂度因为用到了ans数组,所以是 n

/**
 * @param {number[]} nums
 * @return {number[]}
 */
var sortArray = function(nums) {
    return mergeSort(nums, 0, nums.length - 1)
};

//递归,如此会细分到长度只有2的数组才开始
function mergeSort(nums, left, right) {
	//只要index左边超过右边就说明到底了
    if (left >= right) return nums;
    //算出mid的index
    let mid = (left + right) >> 1;
    //连续递归下去,能细分个数为2的层次,然后进行merge,排完最低层次后,再return回上一层,递归回去排序上一层
    mergeSort(nums, left, mid)
    mergeSort(nums, mid + 1, right)
    return merge(nums, left, mid, right)
}

//比较每一次递归里面的两个分段,然后合并
function merge(nums, left, mid, right) {
	//用于记录,完了会滕到原数组里面,相当于temp
    let ans = [];
    //分出两段的起始
    let c = 0, i = left, j = mid + 1;
    
    //如果比较的指针两段都还没走完,这个指针可能是i也可能是j
    while (i <= mid && j <= right) {
    	//谁小就放到ans中
        if (nums[i] < nums[j]) {
            ans[c++] = nums[i++];
        } else {
            ans[c++] = nums[j++]
        }
    }
	
	//到这里就说明,至少有一段已经走完了,把剩下的另一段的,全部放进ans后面就行,都是有序的,因为是从长度2的数组开始合并的
    while (i <= mid) {
        ans[c++] = nums[i++];
    }
    while (j <= right) {
        ans[c++] = nums[j++];
    }

	//把ans放进nums原数组,并返回nums
    for (let i = 0; i < ans.length; i++) {
        nums[i + left] = ans[i];
    }
    return nums;
}

作者:jsyt
链接:https://leetcode-cn.com/problems/sort-an-array/solution/5chong-chang-yong-pai-xu-suan-fa-by-jsyt/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值