基础概念
数据结构
- Data structure
- 存储数据的不同方式
算法
- 算法往往是针对特定数据结构的。
- 同一问题的不同解决方法
如何测算算法的优劣
- 时间测算
- 计算算法时间差
- 未读不够循环来凑
- 空间测算
- Big O 时间复杂度(最差的情况)O(1) ,O(n),n次方等等
- 不考虑必须要做的操作
- 循环、赋初值、程序初始化
- 不考虑常数项
- 不考虑低次项
- 不考虑必须要做的操作
- eg:
选泡插,快归堆希桶计基
如何写算法程序
- 由简单到复杂
- 验证一步走一步
- 多打印中间结果
- 先局部后整体
- 没思路时先细分
- 先粗糙后精细
- 变量更名
- 语句合并
- 边界处理
公共方法
// 查找最大值
function findMaxInList(list,n) {
for (let j = 0; j < n; j++) {
if (list[j] > list[j + 1]) {
swap(list, j, j + 1)
}
}
}
// 转换
function swap (list, i, j) {
let temp = list[i]
list[i] = list[j]
list[j] = temp
}
选择排序
// 选择排序 不稳
function selection () {
let list = [5, 4, 7, 2, 1, 3, 6, 8, 9, 0, 12, 32, 13, 34, 231, 43, 1000] // 不计入算法时间
// n n-1 n
for (let i = 0; i < list.length - 1; i++) {
let minPos = i // n
// n n*n n*n
for (let j = i + 1; j < list.length; j++) { // 最消耗时间
// (n-1)+(n-2)+....+ 1
minPos = list[j] < list[minPos] ? j : minPos
}
swap(list, i, minPos) // n
}
// 总的时间复杂度 O(n²) // 空间复杂度:O(1)
console.log('结果===>', list)
}
// 转换
function swap (list, i, j) {
let temp = list[i]
list[i] = list[j]
list[j] = temp
}
// 执行
selection()
冒泡排序
// 冒泡
function bubble () {
let list = [5, 4, 7, 2, 1, 3, 6, 8, 9, 0, 12, 32]
for (let i = list.length - 1; i > 0; i--) {
findMaxInList(list,i)
}
// 总的时间复杂度 O(n²) // 空间复杂度:O(1)
console.log('结果===>', list)
}
bubble()
插入排序
对于有序的数组最好用
// 插入排序
function insertion () {
let list = [5, 4, 7, 2, 1, 3, 6, 8, 9, 0, 12, 32]
for (let i = 1; i < list.length; i++) {
for (let j = i; j > 0; j--) {
if (list[j] < list[j - 1]) {
swap(list, j, j - 1)
}
}
}
// 总的时间复杂度 O(n²) // 空间复杂度:O(1)
console.log('结果===>', list)
}
insertion()
简单排序总结
- 冒泡:基本不用、太慢
- 选择:基本不用、不稳
- 插入:样本小且有序的时候效率比较高
希尔排序
改进的插入排序
function shell (params) {
let list = [5, 4, 7, 2, 1, 3, 6, 8, 9, 0, 12, 32]
let h = 1
while (h <= list.length) { //使用的是knuth序列
h = h * 3 + 1
}
for (let gap = h; gap > 0; gap=(gap-1)/3) {
for (let i = gap; i < list.length; i++) {
for (let j = i; j > gap - 1; j -= gap) {
if (list[j] < list[j - gap]) {
swap(list, j, j - gap)
}
}
}
}
// 总的时间复杂度 O(n^1.3) // 空间复杂度:O(1)
console.log('结果===>', list)
}
shell()
归并排序
将一个数组反复二分为两个小数组,直到每个数组只有一个元素;然后从最小数组开始,两两按大小顺序合并,直到并为原始数组大小
function merge (params) {
let list = [5, 4, 7, 2, 1, 3, 6, 8, 9, 0, 12, 32]
list = [...sort(list, 0, list.length - 1)]
// 总的时间复杂度 O(n^1.3) // 空间复杂度:O(1)
console.log('结果===>', list)
}
function sort (arr, first, last) {
let temp = []
if (first < last) {
let mid = Math.floor((first + last) / 2);
sort(arr, first, mid, temp); //调用自身处理左边
sort(arr, mid + 1, last, temp); //调用自身处理右边
arr = tempMerge(arr, first, mid, last, temp);
}
return arr;
}
function tempMerge (arr, first, mid, last, temp) {
let i = first
let m = mid;
let j = mid + 1;
let n = last;
let k = 0;
while (i <= m && j <= n) {
if (arr[i] < arr[j]) {
temp[k++] = arr[i++];
} else {
temp[k++] = arr[j++];
}
}
while (i <= m) {
temp[k++] = arr[i++];
}
while (j <= n) {
temp[k++] = arr[j++];
}
for (let l = 0; l < k; l++) {
arr[first + l] = temp[l];
}
return arr;
}
merge()
堆排序
function heap (params) {
let list = [21, 23, 5, 2, 1, 5, 7, 8, 5, 45, 34, 23, 65, 878];
heapSort(list)
console.log('结果===>', list)
}
function heapSort (list) {
let iParent = Math.floor(list.length / 2) - 1
for (let i = iParent; i >= 0; i--) {
maxHeapify(list, i, list.length)
}
for (let i = list.length - 1; i >= 0; i--) {
swap(list, 0, i)
maxHeapify(list, 0, i)
}
return list
}
function maxHeapify (list, index, heapSize) {
while (true) {
let iMax = index
let iLeft = 2 * index + 1
let iRight = 2 * (index + 1)
if (iLeft < heapSize && list[iLeft] > list[iMax]) {
iMax = iLeft
}
if (iRight < heapSize && list[iRight] > list[iMax]) {
iMax = iRight
}
if (iMax != index) {
swap(list, iMax, index)
index = iMax
} else {
break;
}
}
}
heap()
快速排序
function quick () {
let list = [5, 4, 7, 2, 1, 3, 6, 8, 9, 0, 12, 32]
let res = quickSort(list, 0, list.length - 1)
console.log('结果===>', res)
}
function quickSort (list, left, right) {
let partitionIndex
if (left < right) {
partitionIndex = partition(list, left, right)
quickSort(list, left, partitionIndex - 1)
quickSort(list, partitionIndex + 1, right)
}
return list
}
function partition (list, left, right) {
let pivot = left,
index = pivot + 1;
for (var i = index; i <= right; i++) {
if (list[i] < list[pivot]) {
swap(list, i, index);
index++;
}
}
swap(list, pivot, index - 1);
return index - 1;
}
quick()
计数排序
量大但是范围小,如根据年龄排序,高考名次排序等等
function counting (params) {
let list = [7, 6, 8, 3, 4, 2, 1, 2, 6, 9, 5, 4, 6, 5, 2, 8, 7, 5]
let res = countingSort(list, 10) // 固定传入一个最大数
console.log('结果===>', res)
}
function countingSort (list, max) {
let result = []
let count = []
for (let i = 0; i <= max; i++) {
count[i] = 0
}
for (let j = 0; j < list.length; j++) {
count[list[j]]++
}
console.log(count);
for (let k = 0; k <= max; k++) {
while (count[k]-- > 0) {
result.push(k)
}
}
return result
}
counting()
基数排序
多关键字排序
function radix () {
let list = [23, 45, 63, 53, 524, 786, 2, 543, 56, 87, 98, 67, 5, 6, 8]
let max = 0
for (let i = 0; i < list.length; i++) {
max = (list[i] + '').length > max ? (list[i] + '').length : max;
}
let res = radixSort(list, max)
console.log('结果===>', res)
}
function radixSort (list, maxLength) {
let mod = 10; // 10精制
let dev = 1; // 位数
let counter = [];
for (let i = 0; i < maxLength; i++, dev *= 10, mod *= 10) {
for (let j = 0; j < list.length; j++) {
let bucket = parseInt((list[j] % mod) / dev);
if (counter[bucket] == null) {
counter[bucket] = [];
}
counter[bucket].push(list[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) {
list[pos++] = value;
}
}
}
}
return list
}
radix()
桶排序
function bucket () {
let list = [2,1, 3, 4, 63, 4, 21, 54, 65, 75, 86, 97]
let len = list.length
if (len < 2) {
return
}
const bucket = []
list.forEach((one) => {
if (bucket[one] !== undefined) {
bucket[one]++
} else {
bucket[one] = 1
}
});
const newArr = []
bucket.forEach((one, index) => {
if (one !== undefined) {
for (let i = 0; i < one; i++) {
newArr.push(index)
}
}
})
list = [...newArr]
console.log('结果===>', list)
}
bucket()