常见的排序算法

一、冒泡排序

简单描述:

        相邻的两个元素之间进行比较、交换,每一遍都将最大的元素放置最后,直到没有再需要比较的。

算法步骤:

  1. 比较相邻的两个元素,如果第一个比第二个大,就交换,否则不动;
  2. 对每一对相邻元素进行比较,从第一对比到最后一对,最后的元素就是最大的;
  3. 除了最后一个元素,都重复上述操作;
  4. 每一遍都将最大的元素放置最后,直到没有需要比较的。

动图演示:

最好/最坏情况:

        最好正序,O(n);最坏反序,O(n²)。

时间复杂度:

        O(n²)

空间复杂度:

        O(1)

稳定性:

        稳定

JavaScript代码:

function bubbleSort(arr) {
    var len = arr.length;
    for (var i = 0; i < len - 1; i++) {
        for (var j = 0; j < len - 1 - i; j++) {
            if (arr[j] > arr[j+1]) {       
                var temp = arr[j+1];      
                arr[j+1] = arr[j];
                arr[j] = temp;
            }
        }
    }
    return arr;
}

二、选择排序

简单描述:

        每次遍历都选出最小或最大的元素放到前边有序地排列。

算法步骤:

  1. 在未排序的序列中选出最大(小)的元素,存放到排序序列的起始位置;
  2. 从剩余的未排序的序列中再选出最大(小)的元素,放到已排序序列的末尾;
  3. 重复以上操作,直到所有元素都排完。

动画演示:

最好/最坏情况:

        没有最好最坏情况,所有元素都是O(n²)的时间复杂度,数据规模越小越好。

时间复杂度:

        O(n²)

空间复杂度:

        O(1)

稳定性:

        不稳定

JavaScript代码:

function selectionSort(arr){
    var len = arr.length;
    var temp,minIndex;
    for(var i=0;i<len-1;i++){
        minIndex = i;
        for(var j=i+1;j<len;j++){
            if(arr[minIndex]>arr[j]){
                minIndex = j;
            }
        }
        temp = arr[minIndex];
        arr[minIndex] = arr[i];
        arr[i] = temp;
    }
    return arr;
}

三、插入排序

简单描述:

        将没有排序的序列元素,插入到已排序的序列元素中

算法描述:

  1. 把序列的第一个元素堪称有序序列,后边的都看成未排序序列;
  2. 从头到尾扫描未排序序列,将元素插入到有序序列中的合适位置(如果元素相等,插入到相等元素的后边)

动图展示:

最好/最坏情况:

        最好正序,O(n);最坏反序,O(n²)。

时间复杂度:

        O(n²)

空间复杂度:

        O(1)

稳定性:

        稳定

JavaScript代码:

function insertSort(arr){
    var len = arr.length;
    var preIndex,current;
    for(var i=1;i<len;i++){
        preIndex = i-1;
        current = arr[i];
        while(preIndex>=0 && current<arr[preIndex]){
            arr[preIndex+1] = arr[preIndex];
            preIndex--;
        }
        arr[preIndex+1] = current;
    }
    return arr;
}

四、希尔排序

简单描述:

        是插入排序的改进版本,将队列分割成若干个子序列,分别进行直接插入排序。

算法描述:

  1. 选择一个增量序列t1,t2,t3,......,tk,其中ti>tj,tk=1;
  2. 按照增量序列个数k,对序列进行k趟排序;
  3. 每一趟排序,都根据对应的增量ti,把待排序列分割成若干个长度为m的子序列,分别对各个子表进行直接插入排序;

动图展示:

时间复杂度:

        O(n log²n)

空间复杂度:

        O(1)

稳定性:

        不稳定

JavaScript代码:

function shellSort(arr) {
    var len = arr.length,
        temp,
        gap = 1;
    while(gap < len/3) {          
        gap =gap*3+1;
    }
    for (gap; gap > 0; gap = Math.floor(gap/3)) {
        for (var i = gap; i < len; i++) {
            temp = arr[i];
            for (var j = i-gap; j >= 0 && arr[j] > temp; j-=gap) {
                arr[j+gap] = arr[j];
            }
            arr[j+gap] = temp;
        }
    }
    return arr;
}

五、归并排序

简单描述:

        采用分治法的算法思想进行排序

算法描述:

  1. 申请空间,使其大小为两个已经排序序列之和,该空间用来存放合并后的序列;

  2. 设定两个指针,最初位置分别为两个已经排序序列的起始位置;

  3. 比较两个指针所指向的元素,选择相对小的元素放入到合并空间,并移动指针到下一位置;

  4. 重复步骤 3 直到某一指针达到序列尾;

  5. 将另一序列剩下的所有元素直接复制到合并序列尾

动图展示:

时间复杂度:

        O(n log n)

空间复杂度:

        O(n)

稳定性:

        稳定

JavaScript代码:

function mergeSort(arr) {  // 采用自上而下的递归方法
    var len = arr.length;
    if(len < 2) {
        return arr;
    }
    var middle = Math.floor(len / 2),
        left = arr.slice(0, middle),
        right = arr.slice(middle);
    return merge(mergeSort(left), mergeSort(right));
}

function merge(left, right)
{
    var result = [];

    while (left.length && right.length) {
        if (left[0] <= right[0]) {
            result.push(left.shift());
        } else {
            result.push(right.shift());
        }
    }

    while (left.length)
        result.push(left.shift());

    while (right.length)
        result.push(right.shift());

    return result;
}

六、快速排序

简单描述:

        采用分治法的算法思想进行排序,选一个数为基准,小的放前边,大的放后边,再分别将小的和大的子序列递归地进行排序。

算法描述:

  1. 从数列中挑出一个元素,称为 "基准"(pivot);

  2. 重新排序数列,所有元素比基准值小的摆放在基准前面,所有元素比基准值大的摆在基准的后面(相同的数可以到任一边)。在这个分区退出之后,该基准就处于数列的中间位置。这个称为分区(partition)操作;

  3. 递归地(recursive)把小于基准值元素的子数列和大于基准值元素的子数列排序;

动图展示:

时间复杂度:

        O(n log n)

空间复杂度:

        O(log n)

稳定性:

        不稳定

JavaScript代码:

function quickSort(arr, left, right) {
    var len = arr.length,
        partitionIndex,
        left = typeof left != 'number' ? 0 : left,
        right = typeof right != 'number' ? len - 1 : right;

    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) {     // 分区操作
    var pivot = left,                      // 设定基准值(pivot)
        index = pivot + 1;
    for (var 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) {
    var temp = arr[i];
    arr[i] = arr[j];
    arr[j] = temp;
}
function partition2(arr, low, high) {
  let pivot = arr[low];
  while (low < high) {
    while (low < high && arr[high] > pivot) {
      --high;
    }
    arr[low] = arr[high];
    while (low < high && arr[low] <= pivot) {
      ++low;
    }
    arr[high] = arr[low];
  }
  arr[low] = pivot;
  return low;
}

function quickSort2(arr, low, high) {
  if (low < high) {
    let pivot = partition2(arr, low, high);
    quickSort2(arr, low, pivot - 1);
    quickSort2(arr, pivot + 1, high);
  }
  return arr;
}

七、堆排序

简单描述:

        利用堆这种数据结构所设计的一种排序算法

算法描述:

  1. 创建一个堆 H[0……n-1];

  2. 把堆首(最大值)和堆尾互换;

  3. 把堆的尺寸缩小 1,并调用 shift_down(0),目的是把新的数组顶端数据调整到相应位置;

  4. 重复步骤 2,直到堆的尺寸为 1。

动图展示:

时间复杂度:

        O(n log n)

空间复杂度:

        O(1)

稳定性:

        不稳定

JavaScript代码:

var len;    // 因为声明的多个函数都需要数据长度,所以把len设置成为全局变量

function buildMaxHeap(arr) {   // 建立大顶堆
    len = arr.length;
    for (var i = Math.floor(len/2); i >= 0; i--) {
        heapify(arr, i);
    }
}

function heapify(arr, i) {     // 堆调整
    var left = 2 * i + 1,
        right = 2 * i + 2,
        largest = i;

    if (left < len && arr[left] > arr[largest]) {
        largest = left;
    }

    if (right < len && arr[right] > arr[largest]) {
        largest = right;
    }

    if (largest != i) {
        swap(arr, i, largest);
        heapify(arr, largest);
    }
}

function swap(arr, i, j) {
    var temp = arr[i];
    arr[i] = arr[j];
    arr[j] = temp;
}

function heapSort(arr) {
    buildMaxHeap(arr);

    for (var i = arr.length-1; i > 0; i--) {
        swap(arr, 0, i);
        len--;
        heapify(arr, 0);
    }
    return arr;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值