[路飞]_小白算法学习之排序算法~

182 阅读2分钟

选择排序

function selectionSort(arr){
    // minIndex 用来寻找最小元素,
    let minIndex , temp;

    for(let i = 0 ; i<arr.length-1;i++){
        minIndex = i // 设置当前下标为最小元素
        //j 是从当前 i 往后遍历一遍剩下的元素,所以 j 的总长度取 arr 的长度
        //搞清楚双重for循环中i与j的关系便比较好理解此解法
        for(let j=i+1;j<arr.length;j++){
            if(arr[j]<arr[minIndex]){
                minIndex = j
            }
        }

        //找到最小元素后与当前元素的置换位置
        temp = arr[i]
        arr[i]  = arr[minIndex] 
        arr[minIndex] = temp 
    }
    return  arr
}

插入排序

function insertionSort(arr){
    const len = arr.length
    let preIndex,current

    for(let i = 1; i< len ;i++){
        preIndex = i - 1;
        current = arr[i];
        while(preIndex >= 0 && arr[preIndex] > current){
            arr[preIndex + 1] = arr[preIndex];
            preIndex--;
        }
        arr[preIndex + 1]= current
    }
    return arr
}
分析过程:
当输入数组为[3,2,1]时,
i= 1,preIndex = 0 ,current = 2, 数组变更为 [2,3,1] preIndex = -1 ; 
i = 2,preindex = 1,current = 1, 数组变更为 [2,3,3] preIndex = 0 
满足while 循环 继续 数组变更为 [2,2,3]preIndex = -1 
不满足while循环  进行current赋值 [1,2,3] 

冒泡排序

function sort(arr){
  let len = arr.length
    for(let i = 0 ; i<len-1;i++){
        for(let j = 0 ; j<len-1-i;j++){
            if(arr[j]>arr[j+1]){
                let temp = arr[j+1]
                arr[j+1] = arr[j]
                arr[j] = temp
            }
        }
    }
  return arr
}
冒泡排序是进行两两比对,不断的对比将较大的元素不断的往后置换
所以此处注意到j层的循环 取的长度是len-1-i 
如果取len-1 最终答案也是一样的,但是多了很多不必要的已确立位置元素的遍历

希尔排序

希尔排序主要是以间隔来进行插入排序 间隔到最后为1时 再次进行插入排序时的数组已经有一定的有序化程度了,所以效率上对于插入排序有一定的提高

function shellSort(arr){
  let len = arr.length,gap = Math.floor(len/2);
  // gap 即为间隔
  for(gap;gap>0;gap = Math.floor(gap/2)){
    for(let i = gap; i < len; i++){
      let j = i;
      let current = arr[i];
      while(j-gap >=0 && current <arr[j-gap]){
        arr[j] = arr[j-gap];
        j = j-gap
      }
      arr[j] = current
    }
  }
  return arr
}

快速排序

主要是以分组与递归来实现

function quickSort(arr,L,R){
    let len = arr.length;
    let partitionIndex //基准点下标
    let left = typeof L === 'number' ? L : 0
    let right = typeof R === 'number'  ? R : len-1

    if( left < right ){
        partitionIndex = partition(arr, left, right)
        quickSort(arr, left , partitionIndex-1)
        quickSort(arr, partitionIndex+1 , right)

    }
    return arr
}

// 获取基准点
function partition(arr, left, right){
    let pivot = left; //选取以left为基准点
    let index = pivot+1;
    for(let i = index; i <= right ; i++){
        // 遍历的元素与基准点相比较 
        if(arr[i] < arr[pivot]){
            swap(arr, i, index)
            index ++;
        }
    }
    swap(arr,pivot,index-1)
    return index - 1

}

// 置换元素位置
function swap(arr,i,j){
    console.log(i,j,'i,j')
    let temp = arr[i]
    arr[i] = arr[j]
    arr[j] = temp
}

链表

两个有序链表的合并

prehead 为头指针 是为了最后return的时候完整的链表进行输出
prev 是处理过程中用来衔接的指针
由于两个链表已经是有序的,只需按顺序一对一的比较即可
function mergeTwoLists(l1, l2) {
    const prehead = new ListNode(-1);
    let prev = prehead;
    while(l1 !== null && l2 !== null){
        if(l1.val <= l2.val){
            prev.next = l1
            l1 = l1.next
        }else{
            prev.next = l2
            l2 = l2.next
        }
        prev =  prev.next
    }
    prev.next = l1 === null ? l2 : l1 // 由于while的循环条件是&& 所以肯定有一个链表存在还未合并的元素 所以需改变指向指向还存在元素的链表即可
    return prehead.next;
}