算法与数据结构笔记:排序(下)

216 阅读1分钟

选择排序

思路

  1. 首先找出数组中最小的数字,
  2. 将最小的数字位置与当前数组第一个位置的数字进行位置兑换
  3. 。。。以此类推
  4. 将第二个数与剩下的数组中的进行比较,将最小的数字放在第二位置
let sort = (numbers) => {
    //为啥这里是numbers.length-1?
    //思路:假定numbers的长度是4,那么当i=3时:前面三个数字都已经比较过了,最后一个数字的位置自然就固定了
    for (let i = 0; i < numbers.length - 1; i++) {
        console.log(`-----`);
        console.log(`i: ${i}`);
    //1.为啥这里是numbers.slice(i)
    //思路:因为当比较完一次之后,第一个位置是确定了的,在第二次比较时,不需要在和第一个位置的数字进行比较,所以把第一个数字从数组中切除再进行后面的比较
    //2.为啥后面还要加i呢?
    //思路:因为数组切除之后形成的数组,开始位置又是从0开始,这是找到的最小值下标要比原始数组中少i个,所以要加上i,才可以在原始数组中进行交换位置
        let index = minIndex(numbers.slice(i)) + i;
        console.log(`index: ${index}`);
        console.log(`min: ${numbers[index]}`);
        if (index !== i) {
            swap(numbers, index, i);
            console.log(`swap ${index}: ${i}`);
            console.log(numbers);
        }
    }
};
//实现查找最小数字下标的方法
//思路:首先假设第一个数字是最小的,然后去遍历整个数组,当发现有数字比第一个还小的时候,就将index值设置为这个最小值的下标
let minIndex = (numbers) => {
  let index = 0;
  for (let i = 1; i < numbers.length; i++) {
    if (numbers[i] < numbers[index]) {
      index = i;
    }
  }
  return index;
};
//实现交换数组元素的方法
//思路:将数组中第i个值与第j 个值进行交换,借助一个中间变量temp实现
let swap = (array, i, j) => {
  let temp = array[i];
  array[i] = array[j];
  array[j] = temp;
};
let arr = [11, 2, 33, 5, 44, 77, 3, 6];
console.log(arr);
sort.call(null, arr);  

上述代码还是很复杂的,思路清晰,但是实际写的过程中,全是出错的

快速排序

递归思路

  1. 以一个数为基准
  2. 让大于这个数的元素放在后面,让小于这个数的元素放到前面
  3. 那么你指定的这个数的位置就是固定的
  4. 然后你再指定一个数,同样的是小的放前面,大的放后面
  5. 那么指定的数字的位置又是固定的
  6. 。。。。
  7. 最后你就排好序了
let quickSort = (arr) => {
    if (arr.length <= 1) {
        return arr;
    }
    let pivotIndex = Math.floor(arr.length / 2);
    let pivot = arr.splice(pivotIndex, 1)[0];
    let left = [];
    let right = [];
    for (let i = 0; i < arr.length; i++) {
        console.log(`---------`);
        console.log(`pivotIndex:${pivotIndex}`);
        console.log(`i:${i}`);
        console.log(`pivot:${pivot}`);
        if (arr[i] < pivot) {
            left.push.call(left,arr[i]);
            console.log(`left: ${left}`);
            console.log(`right:${right}`);
        } else {
            right.push.call(right,arr[i]);
            console.log(`right:${right}`);
        }
    }
    return quickSort(left).concat([pivot], quickSort(right));
};

let arr1 = [3, 4, 2, 1, 8, 7, 5];
console.log(arr1);
let arr2 = quickSort(arr1);
console.log(arr2);  

归并排序

思路

  1. 将数组左边的排好序,将数组的右边排好序
  2. 再将两个合并起来
  3. 同时,左边的再进行分类,将左边的左边排好序,左边的右边排好序,合并
  4. 同理右边也一样
let mergeSort = (arr) => {
    if (arr.length === 1) {
        return arr;
    }
    let left = arr.slice(0, Math.floor(arr.length / 2));
    let right = arr.slice(Math.floor(arr.length / 2));
    console.log(`-------`);
    console.log(`left:${left}`);
    console.log(`right:${right}`);
    return merge(mergeSort(left), mergeSort(right));
};
let merge = (a, b) => {
    if (a.length === 0) return b;
    if (b.length === 0) return a;
    if (a[0] < b[0]) {
        return [a[0]].concat(merge(a.slice(1), b));
  } else { 
        return [b[0]].concat(merge(a, b.slice(1)));
  }
};

let arr1 = [3, 2, 5, 8, 1, 6];
console.log(arr1);
let arr2 = mergeSort(arr1);
console.log(arr2);  

特别是merge函数,递归不是很好懂,需要画图进行推论

计数排序

思路

  1. 用一个hashTable做记录
  2. 发现数字N,就记作: N:1,如果在发现,就+1
  3. 最后把哈希表的key全打出来,假设N:m , 那么N就需要打印m次
let countSort = (arr) => {
    let hashTable = {};
    let max = 0;
    let result = [];
    for (let i = 0; i < arr.length; i++) {
        //首先判断数组中的第i个值是否是在哈希表里面
        //如果不在,就在哈希表里面记上 arr[i]:1
        //如果在,就在 arr[i]: 1+1
        if (!(arr[i] in hashTable)) {
            hashTable[arr[i]] = 1;
        } else {
            hashTable[arr[i]] += 1;
        }
        //遍历的同时,找出数组中最大的值,并将其赋值给max
        //这里其实就是找出哈希表对象里面,key值最大的,方便后面对哈希表进行遍历
        if (arr[i] > max) {
            max = arr[i];
        }
    }
    
    for (let j = 0; j <= max; j++) {
        //查找key是否在哈希表里面
        if (j in hashTable) {
            //如果j在哈希表里面,再做一次循环,找出有多少个j
            //在对象里面    hashTable[j]:value
            //value就是对应的J出现的次数
            for (let i = 0; i < hashTable[j]; i++) {
                result.push(j);
            }
        }
    }
  return result;
};  

总结

关于排序还需在实践中不断练习,多画图进行思考是关键。