数据结构之排序算法(四)

// 二叉堆
        // 父亲节点大于等于  子节点
        // 是一颗完全二叉树
        function swap(arr, x, y) {
            var temp = arr[x];
            arr[x] = arr[y];
            arr[y] = temp;
        }

        class MaxHeap{

            constructor(capacity) {
                if(arguments.length > 1 ){
                    // 这是参数是  arr , n
                    this.capacity = arguments[1];
                    this.Item = [''].concat(arguments[0])
                    this.count = arguments[1];

                    for(var i=Math.floor(this.count/2); i>=1; i--) {
                        this.shiftDown(i);
                    }

                } else {
                    this.Item = new Array(capacity+1);;
                    this.count = 0;
                    this.capacity = capacity;
                }
            }

            // 返回 数据的大小
            size() {
                return this.count;
            }

            // 判断Item是否是 空的
            isEmpty() {
                return this.count == 0;
            }

            // 添加新元素
            insert (item) {
                // 这个可能会  数组越界
                // 但是js自动可以添加
                
                this.Item[this.count+1] = item;
                this.count++;

                this.shiftUp(this.count)
            }

            shiftUp(count) {
                // 判断父节点 是否比自身节点  大
                while( count > 1 && this.Item[Math.floor(count/2)] < this.Item[count]) {
                    swap(this.Item, Math.floor(count/2), count );
                    count = Math.floor(count/2);
                }
            }


            // 出堆
            extractMax() {
                if( this.count > 0){
                    
                    var x = this.Item[1];
                    this.Item[1] = this.Item.pop();
                    this.count--;
                    
                    this.shiftDown(1)
                    return x;
                }
                return null;
            }

            shiftDown(k) {
                while( 2*k <= this.count) {
                    var j = 2*k;
                    //如果右节点 存在且大于左节点 则j =  j+1
                    if( j+1 <= this.count && this.Item[j+1] > this.Item[j]) {
                        j = j+1;
                    }
                    // 如果父节点 大于子节点最大值  则跳出循环
                    if( this.Item[k] > this.Item[j]) {
                        break;
                    }
                    swap(this.Item, k, j);
                    k=j;
                }
            }

        }

        // 堆排序算法
        //  将n个元素逐个插入到一个空堆中,算法复杂度是O(nlongn)
        function  heapSort(arr, n) {
            var max = new MaxHeap(n);
            for(var i=0; i<n; i++) {
                max.insert(arr[i]);
            }

            for(var i=n-1; i>=0; i--) {
                arr[i] = max.extractMax();
            }

        }

        //  而 heapify 的过程, 算法复杂度是O(n)
        //  就是构造函数中有两个参数的例子
        
        function heapSort2(arr, n) {
            var max2 = new MaxHeap(arr, n);

            for(var i=n-1; i>=0; i--) {
                arr[i] = max2.extractMax();
            }

        }


        // 原地堆 排序
        function __shiftDown(arr, n, i) {

            while( 2*i+1 < n) {
                var j = 2*i+1;
                //如果右节点 存在且大于左节点 则j =  j+1
                if( j+1 < n && arr[j+1] > arr[j]) {
                    j = j+1;
                }
                // 如果父节点 大于子节点最大值  则跳出循环
                if( arr[i] > arr[j]) {
                    break;
                }
                swap(arr, i, j);
                i=j;
            }
        }
        function heapSort3(arr, n) {
            for(var i= Math.floor((n-1)/2); i>=0; i--)
                __shiftDown(arr, n, i)
            for(var i= n-1; i>0; i--) {
                swap(arr, i, 0)
                __shiftDown(arr, i, 0)
            }
            return arr;
        }
        
        
        //生成一个数组
        function generate(n, rangeL, rangR){
            var arr = []
            for(var i=0; i<n; i++){
                var x = Math.floor(Math.random() * (rangR -rangeL+1)) + rangeL;
                arr.push(x);
            }
            return arr;
        }
        
        // 生成一个近乎有序的数组
        function getNearlyArray(arr, swaptimes) {
            for(var i=0;i<swaptimes; i++) {
                var x = Math.floor(Math.random() * arr.length);
                var y = Math.floor(Math.random() * arr.length);
                swap(arr, x, y);
            }
        }


        // 随机的 100000个数组 排序的耗时
        var n = 100000;
        var arr = generate(n, 0, n)
        var arr2 = [].concat(arr);
        var arr3 = [].concat(arr);

        var start = new Date();
        heapSort(arr, n)
        var end = new Date();
        console.log("heapSort用时:" + (end - start) + "毫秒")

        var start2 = new Date();
        heapSort2(arr2, n)
        var end2 = new Date();
        console.log("heapSort2用时:" + (end2 - start2) + "毫秒")

        var start3 = new Date();
        heapSort3(arr3, n)
        var end3 = new Date();
        console.log("heapSort3用时:" + (end3 - start3) + "毫秒")
        

        //稳定排序   对于相等的元素  在排序后,原来靠前的元素依然靠前

猜你喜欢

转载自blog.csdn.net/qq_39081958/article/details/81780224