排序算法的比较

 

 

 

 

 参考:

https://blog.csdn.net/lyhkmm/article/details/78920769

https://blog.csdn.net/u012681635/article/details/80453664

https://www.zhihu.com/people/dong-hua-xue-bian-cheng

 

排序算法:

  1、简单排序:冒泡、选择、插入

    1.1:冒泡排序:两两对比,前大于后,则交换位置,直到把最大的冒泡到顶部。交换O(N^2),比较O(N^2)

      

    1.2:选择排序:取出最小值/最大值位置,与第一个/最后一个位置交换。交换O(N),比较O(N^2)

      

    1.3:插入排序:核心思想是局部有序,将后一个要比较的取出,然后比较判断是否移动(不是交换)。由于局部有序,不需要移动则后面的不需要再比较,且取出的元素赋值到停止比较的位置。效率是简单排序里最高的。交换O(N),比较O(N^2),看起来和选择排序一样,但其实是比冒泡和选择少了一半的,且移动比交换的效率高

      

 

  2、高级排序:希尔、快速、归并、技术、基数、堆、桶

    2.1:希尔排序:插入排序的改进,效率更高。

      主要思路:设置间隔,重新排序,让数字离自己正确的位置更近。

      增量的问题:如何选择合适的间隔?

        希尔的原稿建议初始间隔为 N(数字个数)/ 2,不需要在开始排序前为找合适的增量而进行计算;还有Hibbard、Sedgewick等。

        希尔的效率和增量的选择关系很大,但是不好推断,因为一些增量无法证明。但是最坏情况下,使用原始增量也能达到O(N^2),所以通常会比他小

      第一次gap:

      

 

      第二次gap:

       

 

       第三次gap:

       

 

 

    2.2:快速排序:一般来说,是排序里效率最高的,可以看成高级的冒泡

        一次循环(递归)中,找到元素的正确位置,该元素之后不需要任何移动

        主要思路:分而治之(divide and conquer,D&C):将原问题分解为几个规模较小但类似于原问题的子问题,递归地求解这些子问题,然后在合并这些子问题的解来建立原问题的解。

             取一元素,将大于他的放置于右边,小于的放置于左边,递归该函数

        主要操作:选取枢纽:pivot主元。一般取头、中、尾的中位数

        效率:主要看枢纽的选择,最坏的情况就是枢纽是最右或者最左,其效率等同于冒泡。平均效率是O(N*logN)

        图示的pivot取的是最后一个值,思路基本和下面附属代码类似。

        

 

 

复制代码
 function ArrayList() {
      //属性
      this.array = []
      //方法
      //数据插入
      ArrayList.prototype.insert = function (item) {
        this.array.push(item)
      }

      ArrayList.prototype.toString = function () {
        return this.array.join(' ')
      }

      //定义一个交换变量的函数
      ArrayList.prototype.swap = function (m, n) {
        let temp = this.array[m]
        this.array[m] = this.array[n]
        this.array[n] = temp
      }

      //冒泡
      ArrayList.prototype.bubbleSort = function () {
        for (let n = 0; n < this.array.length; n++) {
          for (let i = 0; i < this.array.length - n; i++) {
            if (this.array[i] > this.array[i + 1]) {
              this.swap(i, i + 1)
            }
          }
        }
      }
      //选择
      ArrayList.prototype.selectionSort = function () {
        let length = this.array.length
        let index = null
        for (let n = 0; n < length; n++) {
          index = 0
          for (let i = 0; i < length - n - 1; i++) {
            if (this.array[index] < this.array[i + 1]) {
              index = i + 1
            }
          }
          //有比他大的值,再和末位交换,否则不操作
          if (index != 0) {
            this.swap(index, length - 1 - n)
          }
        }
      }
      //插入
      ArrayList.prototype.insertionSort = function () {
        if (this.array.length > 1) {
          for (let i = 1; i < this.array.length; i++) {
            let temp = this.array[i]
            //这里大于-1是为了当插入的元素是最后一个时,最后一个else的复制
            for (let j = i - 1; j >= -1; j--) {
              if (temp < this.array[j]) {
                this.array[j + 1] = this.array[j]
              } else {
                this.array[j + 1] = temp
                break
              }
            }
          }
        }

      }
      //希尔
      ArrayList.prototype.shellSort = function () {
        let gap = Math.floor(this.array.length / 2)
        while (gap >= 1) {
          //下面其实就是插入排序,前值的间隔从1变成了gap
          for (let i = gap; i < this.array.length; i++) {
            let temp = this.array[i]
            for (let j = i - gap; j >= -gap; j = j - gap) {
              if (temp < this.array[j]) {
                this.array[j + gap] = this.array[j]
              } else {
                this.array[j + gap] = temp
                break
              }
            }
          }
          gap = Math.floor(gap / 2)
        }

      }
      //快速
      //枢纽选择:头中尾中位数,这个是要递归的,所以要传左右值进来
      ArrayList.prototype.medium = function (left, right) {
        let center = Math.floor((left + right) / 2)
        //先进行简单排序交换
        //顺序执行
        if (this.array[right] < this.array[left]) {
          this.swap(right, left)
        }
        if (this.array[center] < this.array[left]) {
          this.swap(center, left)
        }
        if (this.array[center] > this.array[right]) {
          this.swap(center, right)
        }
        //  把中间值放在第二个位置,或者是倒数第二个位置
        //目的是为了把未判别的值全部放置于右边或者左边,为了接下来的操作
        this.swap(left + 1, center)
        return this.array[left + 1]
      }

      ArrayList.prototype.quickSort = function () {
        this.quick(0, this.array.length - 1)
      }

      ArrayList.prototype.quick = function (left, right) {
        //越界时,退出递归
        if (left >= right) {
          return
        }
        let pivot = this.medium(left, right)

        //记录当前左边值和右边值的位置
        let low = left + 1
        let high = right
        //交换
        while (low < high) {
          while (this.array[low] <= pivot) {
            low++
          }
          while (this.array[high] > pivot) {
            high--
          }
          //这里要先判断low的值是不是还小于high,不然就越界了
          if (low < high) {
            this.swap(low, high)
          }
        }

        //循环结束就是数据都正确放到的枢纽的左右,枢纽换位
        this.swap(left + 1, low - 1)

        //递归,分而治之再处理左右值
        this.quick(left, low - 1)
        this.quick(low, right)

      }
    }
复制代码

 

posted @   Jacky02  阅读(517)  评论(0编辑  收藏  举报
(评论功能已被禁用)
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具
点击右上角即可分享
微信分享提示