js实现快速排序

学习一下快速排序!!!!!!


前言

介绍一下快速排序算法

一、快速排序是什么?

快速排序是一种常用的快速排序算法,它采用了分治法策略。该算法首先将一个数组分成两个子数组,然后对这两个子数组递归执行快速排序,并将结果合并起来。在每次递归调用中,快速排序通过选择数组中的一个基准值,把数组划分成比基准值小和比基准值大的两部分,再对这两部分进行排序。快速排序的平均时间复杂度为O(nlogn),最差时间复杂度为O(n^2)。

快速排序的实现思路如下:

  1. 取一个基准元素(例如数组的第一个元素)作为比较对象。
  2. 把小于等于基准元素的元素放到它的左边,把大于基准元素的元素放到它的右边。
  3. 对左右两个子集重复以上步骤,直至每个集合只剩下一个元素或空集为止。

二、

代码如下(示例):

let arr = [1, 2, 3, 4, 5, 6, 7, 8, 9];
        var sortArray = function (arr) {
            shuffle(arr)//洗牌咯
            return QuickSort(arr, 0, arr.length - 1)
        }//定义了一个名为 sortArray 的函数,其参数为传入的数组 arr。该函数返回调用 QuickSort 函数后得到的结果。
        var QuickSort = (arr, p, q) => {
            if (p >= q) return arr
            let m = partition(arr, p, q)
            QuickSort(arr, p, m - 1)
            QuickSort(arr, m + 1, q)
            return arr
        }//定义了一个名为 QuickSort 的函数,
        //接收三个参数:待排序数组 arr,左边界 p,右边界 q。
        //判断左边界是否大于等于右边界,若成立则直接返回 arr,否则调用 partition(arr, p, q)
        // 函数获取中间索引值,然后将左右两半子数组再次[递归]地调用 QuickSort 函数进行排序,最终返回排好序的 arr 数组。
        var partition = (arr, p, q) => {
            let x = arr[p]
            let i = p + 1
            let j = q
            while (i < j) {
                while (i < j && arr[i] <= x) i++
                while (i < j && arr[j] >= x) j--
                swap(arr, i, j)
            }
            if (arr[j] >= x) j--
            swap(arr, p, j)
            return j
        }//定义了一个名为 partition 的函数,
        //接收三个参数:待排序数组 arr,左边界 p,
        //右边界 q。首先将最左侧元素设为基准数 x,
        //然后定义两个指针 i 和 j 分别指向 p + 1 和 q。
        //进行 while 循环,情况 1:当 i < j 且 arr[i] 小于等于基准数时,i 向右移动;
        //情况 2:当 i < j 且 arr[j] 大于等于基准数时,j 向左移动。然后将 i 和 j 指向的元素交换位置,并不断迭代直到 i >= j 为止。
        //遍历完整个数组后,如果基准数小于等于 arr[j],则将 j 减一。最后交换基准数和 arr[j] 的位置,并将 j 返回。
        var swap = (arr, i, j) => {
            let temp = arr[i]
            arr[i] = arr[j]
            arr[j] = temp
        }//交换函数
        var randOne = (n, m, shuffledArr) => {
            let num = n + Math.floor(Math.random() * (m - n + 1));
            if (shuffledArr[num] === undefined) { // 如果这个数字还没有被选过,就直接返回
                shuffledArr[num] = true;
                return num;
            } else { // 如果这个数字已经被选过了,就找到下一个没有被选过的数字
                while (shuffledArr[num] !== undefined) {
                    num++;
                    if (num > m) num = n;
                }
                shuffledArr[num] = true;
                return num;
            }


        }
        //这行代码定义了一个名为 randOne 的箭头函数,接受两个参数 n 和 m。Math.random() 方法返回一个介于 0 到 1 之间的随机浮点数,
        //乘以整个区间大小 (m - n + 1) 后使用 Math.floor() 进行取整,得到 0 到 (m-n) 之间的一个整数,
        //最后加上 n 得到 [n,m] 区间内的一个整数随机数,并将其返回。

        // var shuffle = (arr) => {
        //     let n = arr.length
        //     let nn = [];
        //     for (let i = 0; i < n; i++) {
        //         let rand = randOne(i, n - 1,nn);
        //         swap(arr, i, rand)
        //     }//传入一个正序的数组,然后生成一个随机的、无序的数组,并返回给调用者。
        //     return arr;//洗牌后结果为[7, 8, 2, 1, 5, 4, 6, 3, 9]

        // }//洗牌函数!:shuffle 的作用是将一个数组随机排序,即将数组中的元素随机打乱顺序。
        //在某些场景下,我们需要对数据进行随机排序以增加其变化性和不确定性,比如随机抽取一定数量的样本、求得随机数等等。
        //使用 shuffle 函数可以非常方便地实现这个需求,从而避免出现重复或者偏好等问题。
        //另外值得注意的是,shuffle 这个函数也被称为 Fisher–Yates shuffle 或者 Knuth Shuffle,是一种经典的洗牌算法。

        var shuffle = (arr) => {
            let n = arr.length;
            let nn = [];
            let shuffledArr = {};
            for (let i = 0; i < n; i++) {
                let randIndex = randOne(0, n - 1, shuffledArr);
                nn.push(arr[randIndex]);
            }

            return nn;
        }
        //定义了一个名为 shuffle 的函数,它接收一个参数 arr,代表需要进行随机重排的数组。箭头函数的语法就是(参数) => { 函数体 }。
        //定义了三个变量:n 存储了数组长度,nn 初始化为空数组用来存放随机后的新数组,shuffledArr 是一个空对象,用于保存已经被随机过的索引值。
        //在循环中,调用 randOne 函数获取一个介于 0 和 n-1 之间的随机整数 randIndex,且确保该索引没有被遍历过。
        //将随机到的元素添加到新数组 nn 的末尾。
        console.log(sortArray(arr));
        //从小到大排好了[1,2,3,4,5,6,7,8,9]
        // console.log(shuffle(arr));






基本框架
sortArray:入口方法
QuickSort:递归方法,负责不停的划分,直到 p q 指针对撞
partition: 划分函数,然后返回中点


补充语法点:

在 JavaScript 中,可以通过对象名称和属性名称来访问对象中的属性。属性名称可以是字符串(用双引号 `" "` 或单引号 `' '` 括起来)或变量名(不用引号括起来)。如果一个属性名称使用双引号或单引号括起来,那么这个属性就被视为一个字符串字面量,对应的值也必须是字符串类型的。

举个例子,假设我们定义了一个空对象 `obj`:
let obj = {};
 

如果要向 `obj` 对象中添加一个 `name` 属性,可以使用以下两种方式:

1. 字面量语法,需要加上双引号或单引号


obj["name"] = "Jack";
 

2. 变量名语法,无需添加引号


let propName = "name";
obj[propName] = "Jack";
 

在本例中,`shuffledArr[num]` 使用的是变量名语法,将 `num` 作为属性名,所以不需要加上双引号或单引号。如果写成 `shuffledArr["num"]`,则会创建一个名为 "num" 的新属性,而不是将 `num` 作为变量填充到属性中。

总之,使用什么语法取决于你需要什么样的行为。如果你要在对象中添加一个固定名称的属性,则使用字面量语法;如果你需要动态地添加属性,则使用变量名语法。

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值