数据结构与算法--排序

153 阅读4分钟

数据结构与算法--排序

大O表示法

O(1):常数的,变化曲线为水平的;

O(long(n)):对数的,变化曲线几乎水平,例如二分法;

O(n):线性的;O(nlog(n)):线性和对数乘积;

O(n^2):平方;O(2^n):指数的

排序算法有很多:

冒泡排序;选择排序;插入排序;归并排序;计数排序counting sort;基数排序radix sort;希尔排序;堆排序;桶排序

简单排序:冒泡排序;选择排序;插入排序

高级排序:快速排序;希尔排序

//创建列表类
function ArrayList() {
    //属性
    this.array = [];
    //方法
    //将数据可以插入到数组中的方法
    ArrayList.prototype.insert = function (item) {
        this.array.push(item);
    }
    //toString
    ArrayList.prototype.toString = function () {
        return this.array.join('-'); //将数组转换为字符串,并且中间以-分隔
    }
    //交换两个位置的数据
    ArrayList.prototype.swap = function (m, n) {
        var temp = this.array[m];
        this.array[m] = this.array[n];
        this.array[n] = temp;
    }
    //简单排序
    //冒泡排序
    //冒泡排序的比较次数:(n-1)+(n-2)+...+1=n(n-1)/2,时间复杂度为O(n^2)
    //冒泡排序的交换次数:如果平均两次比较才需要交换一次(不可能每次比较都交换一次),那么交换次数为n^2/4,时间复杂度为O(n^2)
    ArrayList.prototype.bubbleSort = function () {
        var length = this.array.length;
        for (var i = length - 1; i >= 0; i--) {
            for (var j = 0; j < i; j++) {
                if (this.array[j] > this.array[j + 1]) {
                    this.swap(j, j + 1)
                }
            }
        }
    }
    //选择排序
    //选择排序的比较次数:(n-1)+(n-2)+...+1=n(n-1)/2,时间复杂度为O(n^2)
    //选择排序的交换次数:n-1次,时间复杂度为O(n)
    //选择排序通常认为在执行效率上是高于冒泡排序的。
    ArrayList.prototype.selectionSort = function () {
        var length = this.array.length;
        for (var i = 0; i < length - 1; i++) {
            var min = i;
            for (var j = i + 1; j < length; j++) {
                if (this.array[min] > this.array[j]) {
                    min = j;
                }
            }
            this.swap(min, i);
        }
    }
    //插入排序
    //插入排序是简单排序中效率最好的一种,思路是局部有序,然后找一个标记的数和局部有序的序列中比较并插入
    //插入排序的最多的比较次数1+2+...+n=n*(n-1)/2,平均比较次数为n*(n-1)/4,而冒泡排序和选择排序的平均比较次数为n*(n-1)/2,是插入排序的二倍
    //插入排序的复制(比较并移位)次数,最多为n*(n-1)/2,平均为n*(n-1)/4,而且这种复制一次比冒泡排序和选择排序的那种交换更加节省性能。
    ArrayList.prototype.insertionSort = function () {
        var length = this.array.length;
        //外层循环:从第一个位置开始获取数据,向前面局部有序进行插入
        for (var i = 1; i < length; i++) {
            //内层循环:获取i位置元素,和前面的数据依次进行比较
            var temp = this.array[i];
            while (this.array[i - 1] > temp && i > 0) {
                this.array[i] = this.array[i - 1];
                i--;
            }
            //将temp放置到i位置
            this.array[i] = temp;
        }
    }
    //高级排序
    //希尔排序
    //希尔排序的增量有希尔自己提出的增量、Hibbard增量序列、Sedgewick增量序列
    //效率和增量有关,最坏的时间复杂度是O(n^2),通常情况下都是要好于O(n^2),大多数情况下效率都要好于简单排序,甚至在合适的猪呢个两和某些数量n的情况下,还要好于快速排序
    ArrayList.prototype.shellSort = function () {
        var length = this.array.length;
        //初始化的增量
        var gap = Math.floor(length / 2);
        //while循环,gap不断减小
        while (gap >= 1) {
            //以gap作为间隔进行分组,对分组进行插入排序
            for (var i = gap; i < length; i++) {
                var temp = this.array[i];
                //插入排序代码
                while (this.array[i - gap] > temp && i > gap - 1) {
                    this.array[i] = this.array[i - gap];
                    i -= gap;
                }
                this.array[i] = temp;
            }
            //增量变化
            gap = Math.floor(gap / 2);
        }
    }
    //快速排序
    //ps:取一个随机数这个本身是一个非常耗性能的操作
    //快速排序的效率是O(n*logn)
    //选择枢纽,收、中、尾三个数的中位数
    ArrayList.prototype.median = function (left, right) {
        var center = Math.floor((left + right) / 2);
        if (this.array[left] > this.array[center]) {
            this.swap(left, center);
        }
        if (this.array[center] > this.array[right]) {
            this.swap(center, right);
        }
        if (this.array[left] > this.array[center]) { //这一步的判断是必须的,因为上一步交换完之后不清楚首、中哪个数更大
            this.swap(left, center);
        }
        //将center位置和right-1位置交换,最right肯定大于center,直接不用考虑了
        this.swap(center, right - 1);
        
        return this.array[right - 1]; //这是那个中位数
    }
    //快速排序代码
    ArrayList.prototype.quickSort = function () {
        this.quick(0, this.array.length - 1);
    }
    //递归代码
    ArrayList.prototype.quick = function (left, right) {
        //结束条件
        if (left >= right) return;
        //获取枢纽
        var pivort = this.median(left, right);
        //定义变量,用于记录当前找到的位置
        var i = left;
        var j = right - 1;
        //开始进行交换
        while (true) {
            while (this.array[++i] < pivort) {};
            while (this.array[--j] > pivort) {};
            if (i < j) {
                this.swap(i, j);
            } else {
                break;
            }
        }
        //将枢纽放置在正确的位置,也就是i的位置上
        this.swap(i, right - 1);
        //递归
        this.quick(left, i - 1);
        this.quick(i + 1, right);
    }
}
//测试
var list = new ArrayList();
//插入元素
list.insert(66)
list.insert(88)
list.insert(12)
list.insert(87)
list.insert(100)
list.insert(5)
list.insert(566)
list.insert(23)
alert(list);
// //验证冒泡排序
// list.bubbleSort();
// alert(list);
//验证选择排序
// list.selectionSort();
// alert(list);
// //验证插入排序
// list.insertionSort();
// alert(list);
// //验证希尔排序
// list.shellSort();
// alert(list);
// //验证快速排序
list.quickSort();
alert(list);