zoukankan      html  css  js  c++  java
  • O(n^2)以及O(nlogn)时间复杂度的排序算法

    O(n^2)的算法

    都是做的升序。

    简单选择排序

    思路:每次选择还未排序的区间的最小值和未排序区间的第一个值交换。

     1 function selectSort(arr){
     2     for(let i = 0; i < arr.length; i++){
     3         let minIdx = i;
     4         for(let j = i; j < arr.length; j++){
     5             if(arr[j] < arr[minIdx]){             
     6                 minIdx = j;
     7             }
     8         }
     9         let tmp = arr[i];
    10         arr[i] = arr[minIdx];
    11         arr[minIdx] = tmp;
    12     }
    13     return arr;
    14 }

    插入排序(insertion sort)

    思路:当前位置的值与前面排好序的区间从后往前对比,找到适合的插入位置并插入。

    适用于:近乎有序的排序,在几乎有序的情况下,它的速度会比n(logn)的算法还要快,可以接近O(n),插入排序要优于选择排序

     1 function insertSort(arr){
     2     let tmp;
     3     for(let i = 0; i < arr.length; i++){
     4         for(let j = i - 1; j >= 0; j--){
     5         if(j === 0){
     6             if(arr[i] < arr[j]){
     7                 // 在顺序表中,应该使用副本复制当前的值,采用赋值去修改数组,而不是删除和插入,因为在顺序表中删除和插入的时间复杂度是n
     8                 tmp = arr.splice(i,1)[0];
     9                 arr.splice(j,0,tmp);
    10             }
    11         }else if(arr[i] < arr[j] && arr[i] >= arr[j - 1]){
    12                 tmp = arr.splice(i,1)[0];
    13                 arr.splice(j,0,tmp);
    14             }
    15         }
    16         // 做一个当前函数是否有序的判断
    17         if(isSort(arr)){
    18             return arr;
    19         }
    20     }
    21     return arr;
    22 }

    冒泡排序

    O(nlogn)的算法

    归并排序

    优化:在待排区间的长度小于100时,可以用插入排序

     1 // 自下而上的归并算法,自上而下需要用到递归
     2 function mergeSort(arr){
     3     let arrSort = [],n = arr.length,count = 0;
     4     for(let size = 1; size <= n; size += size){ // size表示当前有序区间的长度
     5         for(let i = 0; i < n; i += size*2){
     6             // 将[i...i+size-1]和[i+size...i+size*2-1]的两个区间融合成一个有序的并添加到arrSort后面
     7             arrSort = arrSort.concat(orderMerge(arr.slice(i,i+size),arr.slice(i+size,((i+size*2) > n? n : (i+size*2)))));
     8         }
     9         arr = arrSort.slice(0);
    10         arrSort.length = 0;
    11     }
    12     return {arr,count};
    13     // orderMerger 函数主要是讲有序的两个表融合成一个有序表
    14     function orderMerge(arr1,arr2){
    15         let arr = [];
    16         let idx1 = 0, idx2 = 0;
    17         while(idx1 < arr1.length && idx2 < arr2.length){
    18             if(arr1[idx1] <= arr2[idx2]){
    19                 arr.push(arr1[idx1++]);
    20             }else{
    21                // 当arr1[index1] > arr2[idx2]的时候就是一个逆序对
    22                 arr.push(arr2[idx2++]);
    23                 count++;
    24             }
    25         }
    26         if(idx1 === arr1.length){
    27             arr = arr.concat(arr2.slice(idx2));
    28         }else{
    29             arr = arr.concat(arr1.slice(idx1));
    30         }
    31         return arr;
    32     }
    33 }

    快速排序

    思想:选择待排序的区间中第一个p数作为参照,大于p的放在p的后面,小于p的放前面。最后将p放在两个区间的中间,递归下去。

    缺点:: 1 在排近乎有序的数组的时候,时间复杂度趋近于O(n^2)

    2 再相同数值很多的数组中,时间复杂度趋近于O(n^2)

    解决方案: 优化缺点1:随机选择参照数p或者待排数组中间的数作为参照数

    优化缺点2-1 :从待排数组两边进行遍历,从左向右遇到>=p的值停顿,在从右向左遇到<=p的值停顿,将两个数交换并i++,j--,知道i == j为止

    优化缺点2-2:三路快速排序,有三个数组,一个数组存放小于p的值,一个存放大于p的值,一个存放等于p的值。

     1 function quickSort(arr){
     2     // 终止条件:当数组长度小于等于1是返回该数组
     3     if(arr.length <= 1){
     4         return arr;
     5     }
     6     // 定义leftSort、rightSort存放小于和大于p的数
     7     let leftSort = [], rightSort =[], midSort = [], odd = 0;
     8     // 遍历arr,将大于p的放在rightSort中,小于p的放在leftSort中
     9     //优化缺点1:选择中间的数做参照并把该数从原数组中删除
    10     let idx = Math.floor(arr.length/2);
    11     let p = arr.splice(idx,1)[0];
    12     for(let i = 0; i < arr.length; i++){
    13         if(arr[i] > p){
    14             rightSort.push(arr[i]);
    15         }else if(arr[i] < p){
    16             leftSort.push(arr[i]);
    17         }else{
    18             // 优化缺点2
    19             if(odd){
    20                 leftSort.push(arr[i]);
    21                   odd = 1;
    22             }else{
    23                 rightSort.push(arr[i]);
    24                 odd = 0;
    25             }
    26         }
    27     }
    28     // 递归leftSort、rightSort
    29     leftSort = quickSort(leftSort);
    30     rightSort = quickSort(rightSort);
    31     // 将leftSort、midSort、rightSort合并成一个数组并返回。
    32     arr = leftSort.concat(p,rightSort)
    33     return arr;
    34 }
    35 
    36 //优化缺点2-2
    37 function quickSort(arr){
    38     if(arr.length <= 1){
    39         return arr;
    40     }
    41     let leftSort = [], rightSort =[], midSort = [];
    42     let idx = Math.floor(arr.length/2);
    43     let p = arr[idx]; // 可以不用删除了
    44     for(let i = 0; i < arr.length; i++){
    45         if(arr[i] > p){
    46             rightSort.push(arr[i]);
    47         }else if(arr[i] < p){
    48             leftSort.push(arr[i]);
    49         }else{
    50             midSort.push(arr[i]);
    51         }
    52     }
    53     arr = quickSort(leftSort).concat(midSort,quickSort(rightSort))
    54     return arr;
    55 }

    扩展

    Merge Sort的思路求逆序对的个数

    mergeSort第21行

    Qiuck Sort求数组中第n大的数
     1 function theNumberN(arr,n){
     2 
     3     let p,idx,
     4         leftSort = [],
     5            midSort = [],
     6         rightSort = [];
     7     while(arr.length > 1){
     8         idx = Math.floor(arr.length/2);
     9         p = arr[idx];
    10         for(let i = 0; i < arr.length; i++){
    11             if(arr[i] < p){
    12                 leftSort.push(arr[i]);
    13             }else if(arr[i] > p){
    14                 rightSort.push(arr[i]);
    15             }else{
    16                 midSort.push(arr[i]);
    17             }
    18         }
    19         if(leftSort.length >= n){
    20             arr = leftSort.slice(0);
    21         }
    22         
    23         else if(leftSort.length+midSort.length >= n){
    24            
    25             return midSort[0];
    26         }
    27         
    28         else{
    29             
    30             arr = rightSort.slice(0);
    31             n = n - leftSort.length - midSort.length;
    32         }
    33             leftSort.length = midSort.length = rightSort.length = 0;
    34 
    35     }
    36     return arr[0];
    37     
    38 }

    或者使用递归

     1 function theNumberN(arr,n){
     2     if(arr.length <= 1){
     3         return arr[0];
     4     }
     5     // 选一个基点p 
     6     let p,
     7         leftSort = [],
     8         midSort = [],
     9         rightSort = [];
    10     // 小于p放leftSort,等于p放midSort,大于放rightSort
    11         p = arr[Math.floor(arr.length/2)];
    12         for(let i = 0; i < arr.length; i++){
    13         if(arr[i] < p){
    14             leftSort.push(arr[i]);
    15         }else if(arr[i] > p){
    16             rightSort.push(arr[i]);
    17         }else{
    18             midSort.push(arr[i]);
    19         }
    20     }
    21     // 如果leftSort.length>n则抛弃midSort和rightSort再找leftSort中第n大的数
    22     if(leftSort.length >= n){
    23         return theNumberN(leftSort,n);
    24     }
    25     // 否则判断leftSort.length+midSort.length>n则抛弃leftSort和rightSort,在midSort中找第n-leftSort.length大的数
    26     else if(leftSort.length+midSort.length >= n){
    27         // theNumberN(midSort,n - leftSort.length);
    28         return midSort[0];
    29     }
    30     // 否则抛弃leftSort和midSort,在rightSort中找第n-leftSort.length-midSort.length大的数
    31     else{
    32         return theNumberN(rightSort,n - leftSort.length - midSort.length);
    33     }   
    34 }
  • 相关阅读:
    centos7 升级 python3
    宿主机休眠后,虚拟机网络ping不通网关
    给微信群和朋友圈里发长视频的方法
    在word2019中使用latex
    anki2.1中使用latex,使用 MathJax 渲染latex格式的数学公式,化学公式
    如何用GoldWave批量删除mp3文件开头65秒?
    一款 CentOS-7 个性化配置脚本
    算法及算法分析
    博客园markdown使用LaTeX数学公式
    数据结构与算法
  • 原文地址:https://www.cnblogs.com/171220-barney/p/8972250.html
Copyright © 2011-2022 走看看