zoukankan      html  css  js  c++  java
  • 秒杀9种排序算法(JavaScript版)

     

    从is(":checked")说起

     

     

     

    *此文所用jQuery版本应大于1.6.1
     
    如何判断一个单选(复选)框是否选中。
    对于刚接触jQuery的人,第一反应必然是。
    <input id="checkbox1" type="checkbox" checked>
    <input id="checkbox2" type="checkbox>
    $("#checkbox1").attr("checked") // checked
    $("#checkbox2").attr("checked") // undefined
    无论是否选中,返回的值一直是 checked 。(至于为什么返回的是checked,那是因为checked属性对应的值只有checked这一个,所以写什么checked=false,checked="true",checked="unchecked" 这些是毫无意义的。都等同于checked="checked",可以参考文档 input标签)
     
    回到正题,我们希望的结果肯定是,如果选中了就返回true,没选中就返回false。
    如果对jQuery比较熟悉,一般会这么处理
    <input id="checkbox1" type="checkbox" checked>
    <input id="checkbox2" type="checkbox>
    $("#checkbox1").is(":checked") // true
    $("#checkbox2").is(":checked") // false
    用is方法传入:checked伪类选择器,解决了这个问题。但是,为什么第一种方法不行呢?
     
     
     
    二、HTML元素属性 和 DOM节点属性
    会造成上面问题的疑问,主要原因是一个html元素,有两种类型属性(不知道这样说是否准确,但是个人认为比较好理解)
     
    一种是DOM节点属性,读取它的方法就是 attr() 方法,拿个input来说
    <input id="checkbox1" type="checkbox" checked data-custom='customattribute'>
    这个input有的4个dom节点属性 id、type、checked、data-custom。
    所以通过attr方法可以拿到这4个属性的值(值和html中写的一样,其中checked的值就是checked,原因上面已解释)
    如果你写不存在的属性,返回的就会是undefined。
     
    第二种是HTML元素属性,这种属性你看不到,但是确实存在,而且大部分情况和DOM节点属性对应的值一样。
    在jQuery中取得这种值的方法是prop();
    看下这个例子就明了了
    <input id="checkbox1" type="checkbox" checked data-custom='customattribute'>
    $("#checkbox1").prop("id") //checkbox1
    $("#checkbox1").prop("type") //checkbox
    $("#checkbox1").prop("checked") //true
    $("#checkbox1").prop("data-custom") // undefined 自定义的DOM节点属性用取HTML元素属性的方法是取不到的
    id和type和attr方法返回的一样。但是checked方法返回的值就不一样了,因为DOM节点属性可以理解为静态的,当页面渲染完,checked属性就确定了,就是checked。而HTML元素属性是动态的,随时可以改变,而且对于checked这个属性,对应的值是true或者false。
     
    同理,a标签的href属性,用prop和attr取出来的也有可能不一样。attr取出的和看到的一样,prop取出的会是完整路径
    <a id="a" href="test.html" class="csstest" style="font-size: 30px;">link</a>
    $("#a").attr("href") // test.html
    $("#a").prop("href") // "file:///E:/jquery/test.html"
    所以,回到最开始的问题。
    自然而然有另外一种解决方法
    <input id="checkbox1" type="checkbox" checked>
    <input id="checkbox2" type="checkbox>
    $("#checkbox1").prop("checked") // checked
    $("#checkbox2").prop("checked") // false
     
    现在,这个问题应该已经很明了了。不过attr和prop不仅支持读取属性的操作,还支持写入属性的操作,我简单测试了下,发现在写入方面,attr和prop似乎差别不大。应该是jQuery做了兼容吧。
     
     
     
    三、从原生Javascript看根本区别
    简而言之把。attr相当于 Element.getAttribute / Element.setAttribute 而 prop相当于 Element['name'] / Element.name 这样。
    就好比 
    <a id="a" href="test.html" class="csstest" style="font-size: 30px;">link</a>
    document.getElementById("a").getAttribute("style")  // font-size: 30px;
    document.getElementById("a").style // CSSStyleDeclaration {0: "font-size", parentRule: null, length: 1, cssText: "font-size: 30px;", alignContent: "", alignItems: ""…}   一种浏览器定义的对象

    秒杀9种排序算法(JavaScript版)

    一:你必须知道的

    1> JS原型

    2> 排序中的有序区和无序区

    3> 二叉树的基本知识

    如果你不知道上面三个东西,还是去复习一下吧,否则,看下面的东西有点吃力。

    二:封装丑陋的原型方法

    Function.prototype.method = function(name, func){
        this.prototype[name] = func;
        return this;
    };

    在下面的排序中都要用到这个方法。

    三:9种排序算法的思路和实现

    1> 插入排序

    基本思路:

    从无序区的第一个元素开始和它前面有序区的元素进行比较,如果比前面的元素小,那么前面的元素向后移动,否则就将此元素插入到相应的位置。

    复制代码
    Array.method('insertSort', function(){
        var len = this.length,
            i, j, tmp;
        for(i=1; i<len; i++){
            tmp = this[i];
            j = i - 1;
            while(j>=0 && tmp < this[j]){
                this[j+1] = this[j];
                j--;
            }
            this[j+1] = tmp;
        }
        return this;
    });
    复制代码

    2> 二分插入排序

    二分插入排序思路:

    先在有序区通过二分查找的方法找到移动元素的起始位置,然后通过这个起始位置将后面所有的元素后移。

    复制代码
    Array.method('bInsertSort', function(){
        var len = this.length,
            i, j, tmp, low, high, mid;
        for(i=1; i<len; i++){
            tmp = this[i];
            low = 0;
            high = i - 1;
            while(low <= high){
                mid = (low+high)/2;
                if(tmp < this[mid]) high = mid - 1;
                else low = mid + 1;
            }
            for(j=i-1; j>=high+1; j--){
                this[j+1] = this[j];            
            }
            this[j+1] = tmp;
        }
        return this;
    });
    复制代码

    3> 希尔排序

    希尔排序思路:

    我们在第 i 次时取gap = n/(2的i次方),然后将数组分为gap组(从下标0开始,每相邻的gap个元素为一组),接下来我们对每一组进行直接插入排序。

    复制代码
    Array.method('shellSort', function(){
        var len = this.length, gap = parseInt(len/2), 
            i, j, tmp;
        while(gap > 0){
            for(i=gap; i<len; i++){
                tmp = this[i];
                j = i - gap;
                while(j>=0 && tmp < this[j]){
                    this[j+gap] = this[j];
                    j = j - gap;
                }
                this[j + gap] = tmp;
            }
            gap = parseInt(gap/2);
        }
        return this;
    });
    复制代码

    4> 冒泡排序

    冒泡排序思想:

    通过在无序区的相邻元素的比较和替换,使较小的元素浮到最上面。

    复制代码
    Array.method('bubbleSort', function(){
        var len = this.lenght,
            i, j, tmp;
        for(i=0; i<len; i++){
            for(j=len-1; j>i; j--){
                if(this[j] > this[j-1]){
                    tmp = this[j-1];
                    this[j-1] = this[j];
                    this[j] = tmp;
                }
            }
        }
        return this;
    });
    复制代码

    5> 改进的冒泡排序

    基本思路:

    如果在某次的排序中没有出现交换的情况,那么说明在无序的元素现在已经是有序了,就可以直接返回了。

    复制代码
    Array.method('rBubbleSort', function(){
        var len = this.length,
            i, j, tmp, exchange;
        for(i=0; i<len; i++){
            exchange = 0;
            for(j=len-1; j>i; j--){
                if(this[j] < this[j-1]){
                    tmp = this[j];
                    this[j] = this[j-1];
                    this[j-1] = tmp;
                    exchange = 1;
                }
            }
            if(!exchange) return this;
        }
        return this;
    });
    复制代码

    6> 快速排序

    快速排序思路:

    1) 假设第一个元素为基准元素 

    2) 把所有比基准元素小的记录放置在前一部分,把所有比基准元素大的记录放置在后一部分,并把基准元素放在这两部分的中间(i=j的位置)

    复制代码
    Array.method('quickSort', function(s, t){
        var i=s, j=t,
            tmp;
        if(s < t){
            tmp = this[s];
            while(i!=j){
                while(j>i && this[j]>tmp) j--;//右—>左
                R[i] = R[j];
                while(i<j && this[j]<tmp) i++;//左—>右
                R[j] = R[i]; 
            }
            R[i] = tmp;
            this.quickSort(s, i-1);
            this.quickSort(i+1, t);
        }
        return this;
    });
    复制代码

    7> 选择排序

    选择排序思路:

    在无序区中选出最小的元素,然后将它和无序区的第一个元素交换位置。

    复制代码
    Array.method('selectSort', function(){
        var len = this.length,
            i, j, k, tmp;
        for(i=0; i<len; i++){
            k = i;
            for(j=i+1; j<len; j++){
                if(this[j] < this[k]) k = j;
            }
            if(k!=i){
                tmp = this[k];
                this[k] = this[i];
                this[i] = tmp;
            }
        }
        return this;
    });
    复制代码

    8> 堆排序

    堆排序是一种树形选择排序方法(注意下标是从1开始的,也就是R[1...n])。

    堆排序思路:

    1) 初始堆:

    将原始数组调整成大根堆的方法——筛选算法:

    比较R[2i]、R[2i+1]和R[i],将最大者放在R[i]的位置上(递归调用此方法到结束)

    2) 堆排序:

    每次将堆顶元素与数组最后面的且没有被置换的元素互换。

    复制代码
    Array.method('createHeap', function(low, high){
        var i=low, j=2*i, tmp=this[i];
        while(j<=high){
            if(j< high && this[j]<this[j+1]) j++; //从左右子节点中选出较大的节点
            if(tmp < this[j]){                    //根节点(tmp)<较大的节点
                this[i] = this[j];
                i = j;
                j = 2*i;
            }else break;
        }
        this[i] = tmp;                            //被筛选的元素放在最终的位置上
        return this;
    });
    
    Array.method('heapSort', function(){
        var i, tmp, len=this.length-1;
        for(i=parseInt(len/2); i>=1; i--) this.createHeap(i, len);
        for(i=len; i>=2; i--){
            tmp = this[1];
            this[1] = this[i];
            this[i] = tmp;
            this.createHeap(1, i-1);
        }
        return this;
    });
    复制代码

    9> 归并排序

    归并排序思路:

    1) 归并

    从两个有序表R[low...mid]和R[mid+1...high],每次从左边依次取出一个数进行比较,将较小者放入tmp数组中,最后将两段中剩下的部分直接复制到tmp中。

    这样tmp是一个有序表,再将它复制加R中。(其中要考虑最后一个子表的长度不足length的情况)

    2) 排序

    自底向上的归并,第一回:length=1;第二回:length=2*length ...

    复制代码
    Array.method('merge', function(low, mid, high){
        var tmp = new Array(), i = low, j=mid+1, k=0;
        while(i<=mid && j<=high){
            if(this[i] <= this[j]){//比较第一部分和第二部分,取较小者
                tmp[k] = this[i];
                i++;
                k++;
            }else{
                tmp[k] = this[j];
                j++;
                k++;
            }
        }
        while(i<=mid){
            tmp[k] = this[i];
            i++;
            k++;
        }
        while(j<=high){
            tmp[k] = this[j];
            j++;
            k++;
        }
        for(k=0,i=low; i<=high; k++,i++) this[i] = tmp[k];
    
        return this;
    });
    Array.method('mergePass', function(length, n){
        var i;
        for(i=0; i+2*length-1<n; i=i+2*length) this.merge(i, i+length-1, i+2*length-1);
        if(i+length-1 < n) this.merge(i, i+length-1, n-1); //考虑到最后一个子表的长度可能小于length,所以要特殊处理一下
    
        return this;
    });
    
    Array.method('mergeSort', function(){
        var len = this.length,
            length;
        for(length=1; length<len; length=2*length) this.mergePass(length, len);
    
        return this;
    });
    复制代码

    四:测试

    复制代码
    var out = function(){
        console.log(arguments);
    }
    var test = [0,1,7,6,3,4,9,8];
    out(test.insertSort(), 'insertSort');
    var test = [0,1,7,6,3,4,9,8];
    out(test.bInsertSort(), 'bInsertSort');
    var test = [0,1,7,6,3,4,9,8];
    out(test.shellSort(), 'shellSort');
    var test = [0,1,7,6,3,4,9,8];
    out(test.bubbleSort(), 'bubbleSort');
    var test = [0,1,7,6,3,4,9,8];
    out(test.rBubbleSort(), 'rBubbleSort');
    var test = [0,1,7,6,3,4,9,8];
    out(test.quickSort(0, test.length-1), 'quickSort');
    var test = [0,1,7,6,3,4,9,8];
    out(test.selectSort(), 'selectSort');
    var test = [0,1,7,6,3,4,9,8];
    out(test.heapSort(), 'heapSort');
    var test = [0,1,7,6,3,4,9,8];
    out(test.mergeSort(), 'mergeSort');
    复制代码
  • 相关阅读:
    生成器函数
    初识函数
    格式化输出
    流程控制-while循环
    流程控制if语句
    Python入门
    Eclipse搭建C++开发环境
    Android SQLite基本用法
    Android拍照后更新相册
    操作系统相册和获取相册路径
  • 原文地址:https://www.cnblogs.com/Leo_wl/p/3362435.html
Copyright © 2011-2022 走看看