算法与数据结构

三种语句搞定所有逻辑

顺序执行语句

  • 语句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)

 *本文为鲲游北冥的原创文章,著作权归本人和饥人谷所有,转载务必注明来源

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值