数据结构与算法学习——排序问题

148 阅读5分钟

三种简单排序和两种复杂排序 使用JavaScript

首先封装一个列表类,来将插入、排序等操作都封装进去

function arrayList(){
    this.array=[];
    //插入方法
    arrayList.prototype.insert=function(item){
        this.array.push(item);
    }
    //打印方法
    arrayList.prototype.print=function(){
        console.log(this.array.join("-"));
    }
    //交换方法(使用次数较多,封装成函数)
    arrayList.prototype.swap=function(n1,n2){
        //传入下标交换即可
        let temp=this.array[n1];
        this.array[n1]=this.array[n2];
        this.array[n2]=temp;
    }
}

简单排序

1、冒泡排序bubbleSort

特点:简单、效率低

思路:越往上气泡越大,对应的越往后数字越大

  • 1、从头到尾依次两两比较
  • 2、如果后面的数比自己小,就交换,把大的数字像冒泡泡一样往后推
  • 3、然后循环,比较到倒数第二个数字为止,直到只剩第一个数

复杂度 比较次数和交换次数都是O(n^2)

arrayList.prototype.bubbleSort=function(){
    //外层循环控制内层循环的结束位置
    for(let x=length-1; x>0; x--){
        //内层循环依次比较、交换
        for(let i=0; i<x; i++){
            if(this.array[i]>this.array[i+1]){
                this.swap(i,i+1);
            }
        }
    }
}

2、选择排序selectionSort

特点:简单、效率高于冒泡排序

思路:每次选择最小的数的索引,依次放到最前面

  • 1、从第一个位置开始,与后面所有数比较,选出最小的位置,记录索引
  • 2、将第一个位置与最小值所在位置交换
  • 3、从第二个开始继续重复上述步骤,直到倒数第二个数

复杂度 比较次数是O(n^2),交换次数是O(n)

 arrayList.prototype.selectionSort=function(){
    let length=this.array.length;
    //从第一个开始依次比较选择最小的值的下标,与第一个交换,内层每次都+1开始循环,外层控制开始索引
    for(let i=0;i<length-1;i++){
        let min=i;
        for(let x=i;x<length;x++){
            if(this.array[x]<this.array[min]){
                min=x;
            }
        }
        this.swap(i,min);
    }
}

3、插入排序insertionSort

特点:简单、效率高于前两者

思路:默认第一个数字有序,之后依次与前面的数比较,保持前面有序

  • 1、第二个位置的数,记录数值,与第一个数比较
  • 2、比前面的数大就停止,小就将值复制到自己的位置,再往前比较
  • 3、循环到最后一个数字为止

复杂度 比较次数是最多O(n^2),复制次数最多是O(n^2),赋值比交换本就效率高

arrayList.prototype.insertionSort=function(){
    let length=this.array.length;
    //默认第一个数字有序,从第二个位置开始向前比较,如果小于,复制移动,大于停止
    //没有确定的内循环次数,内层用while
    for(let i=1;i<length;i++){
        let x=i;
        let temp=this.array[i];
        while(this.array[x-1]>temp && x>0){
            this.array[x]=this.array[x-1];//前一个位置值后移
            x--;
        }
        this.array[x]=temp;
    }
}

复杂排序(复杂度皆不好证明)

1、希尔排序shellSort

特点:是对插入排序的升级 思路:将数据进行分组,组内排序,分组的间隔逐渐减小,当减小到1时就是插入排序,比起插入排序减少了平均比较次数

  • 1、以gap=length/2为第一次分组,组内进行插入排序
  • 2、完成之后每次gap/2为下一次分组
  • 3、直到gap=1为最后一次
 arrayList.prototype.shellSort=function(){
    let length=this.array.length;
    let gap=Math.floor(length/2);
    while(gap>=1){
        for(let i=gap;i<length;i++){
            let x=i;
            let temp=this.array[x];
            while(this.array[x-gap]>temp && x>=gap){
                this.array[x]=this.array[x-gap];
                x-=gap;
            }
            this.array[x]=temp;
        }
        gap=Math.floor(gap/2);
    }
}

2、快速排序quickSort

特点:分而治之 思路:选择一个枢纽,左边放比它小的数,右边放比它大的数,这个位置就是该数字的正确排序位置

  • 1、从0、length-1和中间的mid中选择中位数为枢纽,并将三者排序交换位置
  • 2、将mid与倒数第二个数交换位置,然后将0设置为left,length-3的位置为right
  • 3、两者向中间移动,left遇到大于mid值的停止,right遇到小于停止
  • 4、如果此时left<=right,交换二者位置,继续直到left>right
  • 5、将right所指的位置与mid现在所在的位置交换,就是该数的正确位置
  • 6、使用递归,左边从0,mid-1;右边从mid+1,length-1
//1、寻找枢纽
arrayList.prototype.median=function(left,right){
    let center=Math.floor((left+right)/2);
    if(this.array[left]>this.array[center]){
        this.swap(left,center);
    }
    if(this.array[right]<this.array[center]){
        this.swap(right,center);
    }
    //将枢纽与倒数第二个数交换,因为最后一个数肯定大于枢纽,不必进入第一次排序
    this.swap(center,right-1);
    return this.array[right-1];
}
        //2-2、快排
arrayList.prototype.quickSort=function(){
    this.quick(0,this.array.length-1);
}
arrayList.prototype.quick=function(left,right){//递归的函数
    //第一次根据median把小的放左边,大的放右边
    if(left>=right){return;}
    let pivot=this.median(left,right);
    let i=left;
    let j=right-1;
    while(true){//符合条件直接break
        while(this.array[++i]<pivot){}//此时i的位置是大于pivot的数
        while(this.array[--j]>pivot){}//此时j的位置是小于pivot的数
        if(i<j){
            this.swap(i,j);
        }else{
            break;
        }
    }
    this.swap(i,right-1);//此时i位置上的值就是这个位置的值
    //递归,左右各自分而治之
    this.quick(left,i-1);
    this.quick(i+1,right);
}

总结

快速排序时目前效率最高的排序方式,如果遇到面试或者笔试要求写排序,应当时首选。