zoukankan      html  css  js  c++  java
  • 交换排序-起泡排序、快速排序算法

    交换排序是一类借助交换排序的算法,其主要思想是:在待排序序列中选两个记录,将它们的关键码进行比较,如果反序则交换它们的位置。

    一、起泡排序

    起泡排序是交换排序中最简单的算法,基本思想:两两比较相邻记录的关键码,如果反序则交换,直到没有反序的记录。代码如下

    function bubbleSort(arr){
        var length=arr.length;
        var exchange=length-1,bound,temp;
        while(exchange!=0){
            bound=exchange;
            exchange=0;
            for(var j=0;j<length;j++){
                if(arr[j]>arr[j+1]){
                    temp=arr[j];
                    arr[j]=arr[j+1];
                    arr[j+1]=temp;
                    exchange=j;
                }
            }
        }
        return arr;
    }
    bubbleSort([4,3,5,6]);

    效率:

    时间复杂度:最好:O(n),最坏:O(n^2),平均:O(n^2)。

    空间复杂度:O(1)。

    稳定性:稳定

    备注:冒泡排序,思想和起泡排序一样,但是比较的次数>=起泡排序。代码如下:

    /*冒泡排序*/
    function sort(arr) {
            for (i = 1; i < arr.length; i++) {
                for (j = 0; j < i; j++) {
                    if (arr[j] > arr[i]) {
                        maxTemp = arr[j];
                        arr[j] = arr[i];
                        arr[i] = maxTemp;
                    }
                }
            }
            return arr;
     }
    console.log(sort([5, 100, 6, 3, -12]));

    一、快速排序

    起泡排序的比较和移动是在相邻的位置进行的,记录每次只能后移一个位置,因此总的比较和移动次数比较多,在快速排序中,记录的比较和移动是从两端向中间进行,关键码较大的记录一次就能从前面移动到后面,关键码较小的记录一次就能从后面移到前面,记录移动的距离较远,从而减少了总的比较次数和移动次数,快速排序又称为分区交换排序,基本思想:首先选一个轴值(即比较的基准),将待排序序列分成两部分,左侧记录的关键码均小于或等于轴值,右侧记录的关键码均大于或等于轴值,然后分别对这两个部分重复上述过程知道整个序列有序,这是一个递归的过程。代码如下:

    /*快速排序*/
    function Sort(arr) {    
            if (arr.length <= 1) {
                return arr;
            }
            //取中间数值
            var standardNum = arr.splice(Math.floor(arr.length / 2), 1);
            var leftArr = [];
            var rightArr = [];
            for (var i = 0; i < arr.length; i++) {
                if (arr[i] <= standardNum[0]) {
                    leftArr.push(arr[i]);
                } else {
                    rightArr.push(arr[i]);
                }
            }
            return Sort(leftArr).concat(standardNum, Sort(rightArr));
     }
    Sort([5, 100, 6, 3, -12]); //[-12, 3, 5, 6, 100]

    改进版:

    function quickSort(arr) {
        let swap = (arr, i, j) => {
            let tmp = arr[i];
            arr[i] = arr[j];
            arr[j] = tmp;
        }
        
        let partition = (arr, first, end) => {
            var i = first;
            var j = end;
            while(i < j) {
                while(i < j && arr[i] <= arr[j]) {
                    j--;
                }
                if(i < j) {
                    swap(arr, i, j);
                }
                while(i < j && arr[i] <= arr[j]) {
                    i++;
                }
                if(i < j) {
                    swap(arr, i, j)
                    j--;
                }
            }
            return i;
        }
    
        let sort = (arr, first, end) => {
            if(first < end) {
                mid = partition(arr, first, end);
                sort(arr, first, mid - 1);
                sort(arr, mid + 1, end);
            }
        }
        sort(arr, 0, arr.length - 1);
        return arr;
    }
    var arr = [23, 13, 49, 6, 31, 19, 28]
    quickSort(arr);
    

     效率:

    时间复杂度:最好:O(nlog2n),最坏:O(n^2),平均:O(nlog2n)。

    空间复杂度:O(log2n)~O(n)。

    稳定性:不稳定

    快速排序适用于待排序记录个数很大且原始记录随机排列的情况,平均性能是迄今为止所有排序算法中最好的一种。

    三、利用快排的思想找一个无序数组的中位数

    如果数组长度是奇数,中位数是排序后的第(n+1)/2个元素;若是偶数,中位数是排序后第n/2个元素。

    换个思路:从无序数组中查找第k大的元素。

    利用快速排序的partition函数,任意挑一个元素,以该元素key,划分数组为两部分,key左边元素小于等于key,右边元素大于等于key。

    在第一次partition后,如果左侧元素个数 < k - 1,则在右侧子序列中递归查找;

    如果左侧元素个数 = k-1,则第k大元素即在分点处;

    如果左侧元素个数 > k - 1,则递归地在左侧序列中继续查找。代码如下:

    function findNum(arr) {
        let swap = (arr, i, j) => {
            let tmp = arr[i];
            arr[i] = arr[j];
            arr[j] = tmp;
        }
        
        let partition = (arr, first, end) => {
            var i = first;
            var j = end;
            while(i < j) {
                while(i < j && arr[i] <= arr[j]) {
                    j--;
                }
                if(i < j) {
                    swap(arr, i, j);
                }
                while(i < j && arr[i] <= arr[j]) {
                    i++;
                }
                if(i < j) {
                    swap(arr, i, j)
                    j--;
                }
            }
            return i;
        }
    
        // 第k大的数,如果数组长度奇数,则k = (1+n)/2, 否则 k= n/2
        function findMediate(arr, k, low, high) {
            if(k > high - low + 1) {
                return -1;
            }
            let pos = partition(arr, low, high);
            if(pos - low < k - 1) {
                return findMediate(arr, k - pos - 1, pos + 1, high);
            } else if(pos - low == k - 1) {
                return arr[pos];
            } else {
                return findMediate(arr, k, low, pos - 1);
            }
        }
        
        function main(arr) {
            let res;
            if(arr.length%2 == 1) {
                res = findMediate(arr, (arr.length+1)/2, 0, arr.length-1);
            } else {
                res = findMediate(arr, arr.length/2, 0, arr.length-1);
            }
            return res
        }
        return main(arr);
    }
    
    var arr = [23, 13, 49, 6, 31, 19, 28, 30, 50]
    findNum(arr); // 28
    var arr = [23, 13, 49, 6, 31, 19, 28]
    findNum(arr); // 23
    var arr = [23, 13, 49, 6, 31, 19, 28, 30]
    findNum(arr); // 23
  • 相关阅读:
    Delphi StrUtils-字符串函数RightStr、MidStr、LeftStr
    Delphi 错误:Could not convert variant to type(Null) into type (String)
    Delphi Variants-VarIsEmpty、VarIsNull 判断Variant变量是否为空、是否包含Null值
    Python使用openpyxl读写excel文件
    CentOS7设置为局域网固定ip
    Linux下ps aux命令中STAT的参数含义(转)
    Python生成8位随机字符串的方法分析
    php源码加密方法详解
    普通程序员 与 大牛 的区别 ???
    开始记录前端学习过程中的点点滴滴
  • 原文地址:https://www.cnblogs.com/Iona/p/4734445.html
Copyright © 2011-2022 走看看