算法篇
排序
1、冒泡排序
1.原理:比较两个相邻的元素,将值大的元素交换到右边
2.思路:依次比较相邻的两个数,将比较小的数放在前面,比较大的数放在后面。
(1)第一次比较:首先比较第一和第二个数,将小数放在前面,将大数放在后面。
(2)比较第2和第3个数,将小数 放在前面,大数放在后面。
......
(3)如此继续,知道比较到最后的两个数,将小数放在前面,大数放在后面,重复步骤,直至全部排序完成
(4)在上面一趟比较完成后,最后一个数一定是数组中最大的一个数,所以在比较第二趟的时候,最后一个数是不参加比较的。
(5)在第二趟比较完成后,倒数第二个数也一定是数组中倒数第二大数,所以在第三趟的比较中,最后两个数是不参与比较的。
(6)依次类推,每一趟比较次数减少依次
const BubbleSort = (arr) => {
if (!(arr instanceof Array)) return 'Is not Array';
if (arr.length < 2) return arr;
const length = arr.length;
for (let i = 0; i < length; i++) {
for (let j = 1; j < length - i; j++) {
if (arr[j] < arr[j - 1]) {
const temp = arr[j];
arr[j] = arr[j - 1];
arr[j - 1] = temp;
}
}
}
return arr
}
2、快速排序
const QuickSort = (arr, low, high) => {
let x = arr[low]
let l = low
let r = high
while(l < r) {
while(l < r && arr[r] > x) {
r--
}
while(l < r && arr[l] <= x) {
l++
}
if (l < r) {
const temp = arr[l]
arr[l] = arr[r]
arr[r] = temp
} else {
const temp = arr[low]
arr[low] = arr[l]
arr[l] = temp
const tmpArr = arr
QuickSort(arr, low, l - 1)
QuickSort(arr, r + 1, high)
}
}
}
关于不懂什么是快速排序的可以点击这里去看怎么去实现的。
3、选择排序
选择排序(Selection sort)是一种简单直观的排序算法。它的工作原理是:第一次从待排序的数据元素中选出最小(或最大)的一个元素,存放在序列的起始位置,然后再从剩余的未排序元素中寻找到最小(大)元素,然后放到已排序的序列的末尾。以此类推,直到全部待排序的数据元素的个数为零。选择排序是不稳定的排序方法。(参考百度百科)
const SelectSort = (arr) => {
if (!(arr instanceof Array)) return 'Is not Array';
if (arr.length < 2) return arr;
const length = arr.length;
for (let i = 0; i < length - 1; i++) {
let minIndex = i;
for (let j = i + 1; j < length; j++) {
minIndex = arr[minIndex] > arr[j] ? j : minIndex;
}
const temp = arr[i];
arr[i] = arr[minIndex];
arr[minIndex] = temp;
}
return arr;
}
4、归并排序
归并排序,是创建在归并操作上的一种有效的排序算法。算法是采用分治法(Divide and Conquer)的一个非常典型的应用,且各层分治递归可以同时进行。归并排序思路简单,速度仅次于快速排序,为稳定排序算法,一般用于对总体无序,但是各子项相对有序的数列。
- 分解(Divide):将n个元素分成个含n/2个元素的子序列。
- 解决(Conquer):用合并排序法对两个子序列递归的排序。
- 合并(Combine):合并两个已排序的子序列已得到排序结果。
-----------------------------------------------------------------------------------------
const MergeSort = (arr) => {
if (!(arr instanceof Array)) return 'Is not Array';
if (arr.length < 2) return arr;
const middle = Math.floor(arr.length / 2);
const left = arr.slice(0, middle);
const right = arr.slice(middle);
return merge(MergeSort(left), MergeSort(right));
}
const merge = (left, right) => {
let 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());
if (left.length) result = [...result, ...left];
// while (right.length) result.push(right.shift());
if (right.length) result = [...result, ...right];
return result;
}
5、堆排序
const HeapSort = (arr) => {
if (!(arr instanceof Array)) return 'Is not Array';
if (arr.length < 2) return arr;
const length = arr.length;
const stap = Math.floor(length / 2) - 1;
for (let i = stap; i >= 0; i--) {
heapify(arr, i, length);
}
for (let i = length - 1; i >= 0; i--) {
const temp = arr[0];
arr[0] = arr[i];
arr[i] = temp;
//调整堆
heapify(arr, 0, i);
}
return arr;
}
const heapify = (arr, i, size) => {
const left = 2 * i + 1;
const right = left + 1;
let maxIndex = i;
//先判断左节点还否超出
if (left < size && arr[left] > arr[maxIndex]) maxIndex = left;
//有节点是否超出 找出最大的子节点
if (right < size && arr[right] > arr[maxIndex]) maxIndex = right;
if (maxIndex !== i) {
const temp = arr[i];
arr[i] = arr[maxIndex];
arr[maxIndex] = temp;
//递归调整
heapify(arr, maxIndex, size);
}
return arr
}
堆排序比较复杂,如果有不理解的可以点击这里
6、插入排序
const InsertionSort = (arr) => {
if (!(arr instanceof Array)) return 'Is not Array';
if (arr.length < 2) return arr;
for (let i = 1; i < arr.length; i++) {
let before = i - 1;
let after = i;
while (arr[after] < arr[before] && before >= 0) {
const temp = arr[after];
arr[after] = arr[before];
arr[before] = temp;
const a = arr;
before--;
after--;
}
}
return arr
}
7、希尔排序
const ShellSort = (arr) => {
if (!(arr instanceof Array)) return 'Is not Array';
if (arr.length < 2) return arr;
const length = arr.length;
let gap = Math.floor(length / 2);
while (gap) {
for (let i = gap; i < length; i++) {
let before = i - 1;
let after = i;
while (arr[after] < arr[before] && before >= 0) {
const temp = arr[after];
arr[after] = arr[before];
arr[before] = temp;
const a = arr;
before--;
after--;
}
}
gap = Math.floor(gap / 2);
}
return arr;
}
8、基数排序
const RadixSort = (arr) => {
if (!(arr instanceof Array)) return 'Is not Array';
if (arr.length < 2) return arr;
const length = arr.length;
// 找出最大值
let max = arr[0];
for (let i = 0; i < length; i++) {
if (arr[i] > max) max = arr[i];
}
//找出最大位数
let maxDigit = 0;
while (max != 0) {
max = parseInt(max / 10);
maxDigit++;
}
let dev = 1, mod = 10, counter = [];
for (let i = 0; i < maxDigit; i++, dev *= 10, mod *= 10) {
for (let j = 0; j < length; j++) {
let bucket = parseInt((arr[j] % mod) / dev);
if (counter[bucket] == null) counter[bucket] = [];
counter[bucket].push(arr[j]);
}
let pos = 0;
for (let j = 0; j < counter.length; j++) {
let value = null;
if (counter[j] != null) {
while ((value = counter[j].shift()) != null) {
arr[pos++] = value;
}
}
}
}
return arr;
}
9、计数排序
思想
- 找出待排序的数组中最大和最小的元素。
- 统计数组中每个值为 i 的元素出现的次数,存入新数组 countArr 的第 i 项。
- 对所有的计数累加(从 countArr 中的第一个元素开始,每一项和前一项相加)。
- 反向填充目标数组:将每个元素 i 放在新数组的第 countArr[i] 项,每放一个元素就将 countArr[i] 减去 1 。
关键在于理解最后反向填充时的操作。
使用条件
- 只能用在数据范围不大的场景中,若数据范围 k 比要排序的数据 n 大很多,就不适合用计数排序。
- 计数排序只能给非负整数排序,其他类型需要在不改变相对大小情况下,转换为非负整数。
- 比如如果考试成绩精确到小数后一位,就需要将所有分数乘以 10,转换为整数
------------------------------------------------------------------------------------------------
const CountSort = (arr) => {
if (!(arr instanceof Array)) return 'Is not Array';
if (arr.length < 2) return arr;
const length = arr.length;
let result = [], count = [], min = arr[0], max = arr[0];
for (let i = 0; i < length; i++) {
count[arr[i]] = count[arr[i]] ? count[arr[i]] + 1 : 1;
min = min <= arr[i] ? min : arr[i];
max = max >= arr[i] ? max : arr[i];
}
for (let i = min; i < max; i++) {
count[i + 1] = (count[i + 1] || 0) + (count[i] || 0);
}
for (let i =length -1; i >= 0; i--) {
result[count[arr[i]] - 1] = arr[i];
count[arr[i]]--;
}
return result;
}
10、桶排序
const BucketSort = (arr, bucketSize) => {
if (!(arr instanceof Array)) return 'Is not Array';
if (arr.length < 2) return arr;
let i;
let minValue = arr[0];
let maxValue = arr[0];
for (i = 1; i < arr.length; i++) {
if (arr[i] < minValue) {
minValue = arr[i]; // 输入数据的最小值
} else if (arr[i] > maxValue) {
maxValue = arr[i]; // 输入数据的最大值
}
}
//桶的初始化
let DEFAULT_BUCKET_SIZE = 5; // 设置桶的默认数量为5
bucketSize = bucketSize || DEFAULT_BUCKET_SIZE;
let bucketCount = Math.floor((maxValue - minValue) / bucketSize) + 1;
let buckets = new Array(bucketCount);
for (i = 0; i < buckets.length; i++) {
buckets[i] = [];
}
//利用映射函数将数据分配到各个桶中
for (i = 0; i < arr.length; i++) {
buckets[Math.floor((arr[i] - minValue) / bucketSize)].push(arr[i]);
}
arr.length = 0;
for (i = 0; i < buckets.length; i++) {
insertionSort(buckets[i]); // 对每个桶进行排序,这里使用了插入排序
for (let j = 0; j < buckets[i].length; j++) {
arr.push(buckets[i][j]);
}
}
return arr;
}
查找
1、普通查找
2、带有哨兵的普通查找
3、二分查找
未完待续。。。