选择排序
思路
- 首先找出数组中最小的数字,
- 将最小的数字位置与当前数组第一个位置的数字进行位置兑换
- 。。。以此类推
- 将第二个数与剩下的数组中的进行比较,将最小的数字放在第二位置
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);
上述代码还是很复杂的,思路清晰,但是实际写的过程中,全是出错的
快速排序
递归思路
- 以一个数为基准
- 让大于这个数的元素放在后面,让小于这个数的元素放到前面
- 那么你指定的这个数的位置就是固定的
- 然后你再指定一个数,同样的是小的放前面,大的放后面
- 那么指定的数字的位置又是固定的
- 。。。。
- 最后你就排好序了
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);
归并排序
思路
- 将数组左边的排好序,将数组的右边排好序
- 再将两个合并起来
- 同时,左边的再进行分类,将左边的左边排好序,左边的右边排好序,合并
- 同理右边也一样
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函数,递归不是很好懂,需要画图进行推论
计数排序
思路
- 用一个hashTable做记录
- 发现数字N,就记作: N:1,如果在发现,就+1
- 最后把哈希表的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;
};
总结
关于排序还需在实践中不断练习,多画图进行思考是关键。