三种语句搞定所有逻辑
顺序执行语句
- 语句1
- 语句2
条件判断语句
- if...then...else...
- if...else if...else...
循环语句
- while...do...
- for i from 1 to n...
- 逻辑很重要
- 用三种语句表达逻辑
- 用图和伪代码表示三种语句
用流程图找出最大数
数据结构
- 就是数据与数据之间的关系和结构
- 数据结构=数据形式+操作
- 不同形式的数据暴露不同的操作
选择排序
找出两个数中较小的一个
普通代码
let minOf2 = (numbers) => { if ( number[0] > number[1] ) { return number[1] } else { return number[0] } }
优化代码
let minOf2 = numbers => number[0] < number[1] ? return number[0]: number[1]
析构赋值优化
let minOf2 = ([a,b]) => a<b ? a : b
调用
minOf2.call(null, [1, 2])
JS 内置的API
- Math
- Math 不是构造函数,只是普通的对象
Math.min (1,2) Math.min.call (null,1,2) Math.min.apply (null, [1,2])
找出三个数中最小的一个
let minOf3 = ([a,b,c]) => {
return minOf2 ([a,minOf2([b,c])])
}
找出四个数中最小的一个
let minOf4 = ([a,b,c,d]) => {
return minOf2([a,minOf3([b,c,d])])
}
用递归找出最小的数字
let min = (numbers) => {
if (numbers.length > 2) {
return min([numbers[0], min(numbers.slice(1))])
} else {
return Math.min.apply(null, numbers)
}
}
递归
递归的特点
- 函数不停调用自己,每次调用的参数略有不同
- 当满足某个简单的条件时,则实现一个简单的调用,最终算出结果
- 可以用带入法或者调用栈快速理解
选择排序
sort() 方法用原地算法对数组的元素进行排序,并返回数组
长度为2的数组排序
let sort2 = ([a,b]) =>
a<b ? [a,b] : [b,a]
长度为3的数组排序
let sort3 = (numbers) => {
let index = minIndex([numbers])
let min = numbers[index]
numbers.splice (index,1)
return [min].concat(sort2(numbers))
}
长度为4的数组排序
let sort4 = (numbers) => {
let index = minIndex (numbers)
let min = numbers[index]
numbers.splice (index,1)
return [min].concat(sort3(numbers))
}
任意长度的数组排序(递归)
let sort = (numbers) => {
if(numbers.length > 2){
let index = minIndex(numbers)
let min = numbers[index]
numbers.splice(index,1)
return [min].concat(sort(numbers))
}else {
return numbers[0] < number[1] ? numbers : numbers.reverse()
}
}
任意长度的数组排序(循环)
- 所有的递归都能改为循环
- 循环时会有很多细节
let sort = (numbers) => {
for (let i = 0; i < numbers.length - 1; i++) {
console.log(`----`)
console.log(`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)
}
}
return numbers
}
let swap = (array, i, j) => {
let temp = array[i]
array[i] = array[j]
array[j] = temp
}
let minIndex = (numbers) => {
let index = 0
for (let i = 1; i < numbers.length; i++) {
if (numbers[i] < numbers[index]) {
index = i
}
}
return index
}
sort ([8,23,2,34,55,43])
快速排序
以某某为基准,小的在前,大的在后
任意长度的数组排序
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++) {
if (arr[i] < pivot) {
left.push(arr[i])
} else {
right.push(arr[i])
}
}
return quickSort(left).concat(
[pivot], quickSort(right))
}
归并排序
不以某某为基准,左边一办排好序,右边一半排好序,合并左边和右边
任意长度的数组排序
let mergeSort = arr => {
let k = arr.length
if (k === 1) {
return arr
}
let left = arr.slice(0, Math.floor(k / 2))
let right = arr.slice(Math.floor(k / 2))
return merge(mergeSort(left), mergeSort(right))
}
let merge = (a, b)
if (a.length === 0) return b
if (b.length === 0) return a
return a[0] > b[0] ?
[b[0]].concat(merge(a, b.slice(1))) :
[a[0]].concat(merge(a.slice(1), b))
}
计数排序
- 用一个哈希表做记录
- 发现数字 N 就记 N:1,再次发现 N 就加 1
- 最后把哈希表的 key 全部打出来,假设 N:m,那么N需要打印 m 次
- 只遍历数组一遍,不过还要额外遍历一次 hashTable
- 这叫做空间换时间
任意长度的数组排序
let countSort = arr => {
let hashTable = {},
max = 0,
result = []
for (let i = 0; i < arr.length; i++) {
if (!(arr[i] in hashTable)) {
hashTable[arr[i] = 1]
} else {
hashTable[i] += 1
}
}
if (arr[i] > max) {
max = arr[i]
}
for (let j = 0; j <= max; j++) {
if (j in hashTable) {
for (let i = 0; i < hashTable[j]; i++) {
result.push(j)
}
}
}
return result
}
几种排序的时间复杂度对比
- 选择排序 O (n^2)
- 快速排序 O (n log2 n)
- 归并排序 O (n log2 n)
- 计数排序 O (n+max)
冒泡排序
- 比较相邻的元素。如果第一个比第二个大,就交换他们两个
- 对每一对相邻元素作同样的工作,从开始第一对到结尾的最后一对。这步做完后,最后的元素会是最大的数
- 针对所有的元素重复以上的步骤,除了最后一个
- 持续每次对越来越少的元素重复上面的步骤,直到没有任何一对数字需要比较
任意长度的数组排序
let bubbleSort = arr => {
for(let i = 0; i < arr.length - 1; i++){
for(let j = 0; j < arr.length - i -1; j++) {
if(arr[j] > arr[j + 1]) {
let temp = arr[j]
arr[j] = arr[j + 1]
arr[j + 1] = temp
}
}
}
return arr
}
插入排序
- 将第一待排序序列第一个元素看做一个有序序列,把第二个元素到最后一个元素当成是未排序序列
- 从头到尾依次扫描未排序序列,将扫描到的每个元素插入有序序列的适当位置。(如果待插入的元素与有序序列中的某个元素相等,则将待插入元素插入到相等元素的后面
任意长度的数组排序
let insertSort = arr => {
let length = arr.length;
for (let i = 1; i < length; i++) {
let temp = arr[i]
let j = i;
for (; j > 0; j--) {
if (temp >= arr[j - 1]) {
break
}
arr[j] = arr[j - 1]
}
arr[j] = temp
}
return arr
}
希尔排序
希尔排序是按一定的间隔对数列进行分组,然后在每一个分组中做插入排序;随后逐次缩小间隔,在每一个分组中做插入排序...直到间隔等于1,做一次插入排序后结束
任意长度的数组排序
let shellSort = arr => {
for (let gap = Math.floor(arr.length / 2); gap > 0; gap = Math.floor(gap / 2)) {
for (let i = gap; i < arr.length; i++) {
let j = i;
let temp = arr[j];
for (; j > 0; j -= gap) {
if (temp >= arr[j - gap]) {
break;
}
arr[j] = arr[j - gap];
}
arr[j] = temp;
}
}
return arr;
}
数据结构
队列(Queue)
- 【先进先出的数组】(FIFO)
- queue.push 为入队
- queue.shift 为出队
栈(Stack)
- 【后进先出】(LIFO)
- JS 函数的调用栈 call stack 就是一个栈
链表(Linked List)
- list = create (value)
- node = get (index)
- append = (node,value)
- remove (node)
- travel (list,fn)
双向链表
每个节点有一个 previous 指向上一个节点
循环链表
最后一个节点的 next 指向头节点
哈希表(Hashtable)
key-value pairs
哈希是什么?
哈希一般叫做散列,意思就是把一堆任意长度的字符串、数字或者二进制输入通过一定的算法(非常多的哈希算法)生成固定长度的一个数字(字符串)。因为算法原因,不同的输入就会得到不同的哈希值。
哈希表是什么?
哈希表一般叫做散列表,就是通过把键值计算出 hash 值后,通过 hash 值映射到表里面的某个位置。那么同样的键值,下次访问或者修改都是同一个映射位置,不同的键值因为计算出 hash 值不一样映射的位置也会不同。
什么是哈希冲突(哈希碰撞)?
因为哈希值是通过一定算法生成的,那么就有一定的可能出现不同的输入得到的 hash 值是一样的,就算我们可以通过调整算法尽量减少这种情况,但是也不可完全避免。发生这种情况后,我们就会出现两个不同的键值被映射到同一个位置了,这就是哈希冲突。
树(Tree)
一个链多个
- let tree = createTree(value)
- let node = createNode(value)
- addChild(tree, node)
- removeChild(nodel, node2)
- travel(tree)
*本文为鲲游北冥的原创文章,著作权归本人和饥人谷所有,转载务必注明来源