对数据结构和算法的总结和思考(二)–简单排序算法

释放双眼,带上耳机,听听看~!
冒泡排序

提起简单排序就不得不先提冒泡排序,为何,简单。只有简单的方法才有可能成为最优秀的方法,无疑,冒泡排序已经具备了简单的潜质。冒泡排序的实现原理是循环然后挨个比较相邻元素,不废话,直接上代码:

先附上一个swap.js的代码:

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

module.exports = swap;

基本实现

let swap = require('./swap.js');
function bubble(arr) {
    for (let i = 0; i < arr.length; i ++) {
        for (let j = 0; j < arr.length - 1 - i; j ++ ) {
            if (arr[j] > arr[j + 1]) {
                swap(arr, j, j + 1);
            } 
        }
    }

    return arr;
}

let arr = [7,11, 4,2, 3, 75, 63, 2, 9,1, 32, 3, 75, 6, 23, 9,1, 34, 14, 10];

console.log(bubble(arr))

这就是最简单的冒泡排序,但是显然不够,如果待排序的数组为顺序结构,这个排序方法会做很多无用功,下面是一次优化的代码:

let swap = require('./swap.js');
function bubble(arr) {
    let hasSwap = true;//标识符,区分是否有待交换的数据。
    for (let i = 0; i < arr.length && hasSwap; i ++) {
        hasSwap = false
        for (let j = 0; j < arr.length - 1 - i; j ++ ) {
            if (arr[j] > arr[j + 1]) {
                swap(arr, j, j + 1);
                hasSwap = true;
            } 
        }
    }

    return arr;
}

let arr = [7,11, 4,2, 3, 75, 63, 2, 9,1, 32, 3, 75, 6, 23, 9,1, 34, 14, 10];

console.log(bubble(arr))

经过一次优化,已经能够处理整个数组有序的情况了,但是,是否可以继续优化呢?可以的,例如每次排序之后数组最后的部分都是大元素,我们是否可以给定一个标识位置的变量用来控制数组已经排序到了哪里,下面是具体实现:

et count = 0;
function bubble(arr) {
    let flag = arr.length;
    let swapPos; //标识排序位置。
    for (let i = 0; i < arr.length; i ++) {
        swapPos = 0;
        for (let j = 0; j < flag - 1; j ++ ) {
            if (arr[j] > arr[j + 1]) {
                swap(arr, j, j + 1);
                swapPos = j + 1;
            } 
        }
        flag = swapPos;
    }

    return arr;
}

let arr = [7,11, 4,2, 3, 75, 63, 2, 9,1, 32, 3, 75, 6, 23, 9,1, 34, 14, 10];

console.log(bubble(arr));

经过两次优化后的冒泡排序,表现比基本的已经好了很多。

简单选择排序

简单选择排序的原理是先选出最大或最小值,然后选出次大或次小值,简单选择排序是移动元素次数最少的排序方式。
const swap = require(‘./swap.js’);

let count = 0;
function select(arr) {
    for (let i = 0; i < arr.length - 1; i ++) {
        min = i;
        for (let j = i + 1; j < arr.length; j ++) {
            count ++;
            if (arr[j] < arr[min]) {
                min = j;//此处找出最小值的index
            }
        }
        if (min !== i) {
            swap(arr, i, min);
        }
    }
    return arr;
}

let arr = [];
for (let i = 0; i < 100; i ++) {
    arr.push(parseInt(Math.random() * 100));
}
console.log(select(arr));
console.log(count);

这个就不单独讲解优化了,主要代码简单,只要注意 min = j;//此处找出最小值的index 这一行,不要直接交换元素就行了。

简单插入排序

插入排序的原理就和打扑克牌一样,你先摸了一张牌,然后再摸一张,这张牌和第一张比较下,就知道放到哪里了。然后再摸第n张,这一张和前面n-1张比较下就知道这张放哪里了。

下面是代码实现:

let swap = require('./swap.js');
let count = 0;
function insert(arr) {
    for (let i = 1; i < arr.length; i ++) {
        let flag = arr[i],
            index = i,
            j = i - 1;
        if (arr[j] > arr[i]) {
            for (j; j >= 0 && arr[j] > flag; j --) {
                count ++;
                arr[j + 1] = arr[j];
                index = j;
            }
            arr[index] = flag;
        }

    }

    return arr;
}

let arr = [];
for (let i = 0; i < 100; i ++) {
    arr.push(parseInt(Math.random() * 100));
}
console.log(insert(arr));
console.log(count);

由于插入排序的原理是先让插入前的元素有序,所以在查找插入位置时,可以进行优化,可以采用比较高效的二分查找法,而不是顺序查找法的方式。下面是优化后的代码:

function binaryInsertionSort(arr, index) {
    console.time('二分插入排序耗时:')
    let count = index || 0;

    for (let i = 1; i < arr.length; i ++) {
        let left = 0, right = i - 1, middle;
        let key = arr[i];
        //二分查找法,找到待插入的位置
        while (left <= right) {
            middle = parseInt((left + right) / 2);
            if (key < arr[middle]) {
                right = middle - 1;
            } else {
                left = middle + 1;
            }
        }
        // 插入
        for (let j = i - 1; j >= left; j --) {
            arr[j + 1] = arr[j];
        }
        arr[left] = key;
    }
    console.timeEnd('二分插入排序耗时:')
    return arr;
}

let sortArr = [];
for (let i = 0;i < 100; i ++) {
    sortArr.push(parseInt(Math.random() * 100));
}
console.log(binaryInsertionSort(sortArr));

以上就是三种简单排序算法,我想也是大家最喜欢,用得最顺手的算法。但是这三种简单算法在数据量较少时表现尚可,在数据量较多的时候并不高效,并且平均查找时间均在O(n^2)。如果不熟悉大O表示法的童鞋可以自行搜索,我这里就不展开讲了。以上就是这次分享的内容,thx。

【转自慕课】https://www.imooc.com

Python

慕课小伙伴的一个问题,用python读取文件的指定段落

2022-3-3 15:51:08

Python

再出发,如何将Devops真正落地(篇1-总结篇)

2022-3-3 15:56:46

搜索