数据结构 - JavaScript

数据结构 - Javascirpt

准备工作

全程使用 VScode + Typescript

调试环境搭建

Vscode typescript 配置

.vscode/launch.json

{
    // 使用 IntelliSense 了解相关属性。 
    // 悬停以查看现有属性的描述。
    // 欲了解更多信息,请访问: https://go.microsoft.com/fwlink/?linkid=830387
    "version": "0.2.0",
    "configurations": [
        {
            "type": "node",
            "request": "launch",
            "name": "ts launch",
            "runtimeExecutable": "ts-node",
            "runtimeArgs": [],
            "args": [
              	// 当前文件
                "${relativeFile}"
            ]
        }
    ]
}

.tsconfig.json

...
// 需要打开
sourceMap: map
...

代码格式化

EditorConfig + Prettier

安装插件

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-b4BU4fji-1606050564274)(/Users/mac/Documents/note/数据结构与算法/images/数据结构重相识/image-20201121200113792.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-5uT2ms7A-1606050564281)(/Users/mac/Documents/note/数据结构与算法/images/数据结构重相识/image-20201121200234070.png)]

.editorconfig

# EditorConfig is awesome: https://EditorConfig.org

root = true

# 作用于所有的 js、ts 文件
[*.{js,ts}]
# 间隔类型
indent_style = space
# 间隔大小
indent_size = 4
# 换行符
end_of_line = lf
# 字符集边编码
charset = utf-8
trim_trailing_whitespace = true
# 在行尾插入空行
insert_final_newline = true
# 单、双引号问题
quote_type = single

prettier.config.js

module.exports = {
	semi: false,
	useTabs: true,
	indent_size: 4,
	arrowParens: 'avoid',
	trailingComma: 'none'
}

后进先出

img

使用场景

  • 所有用到后进先出特点的场景
  • JavaScript 函数执行栈

实例

队列

与栈相似,但是队列是一头进,另一头出 (先进先出 )

使用场景

  • Javascript 异步任务队列

实例

链表

元素之间无顺序可言,通过元素前后指针相连,连成一条链表

使用场景

遍历链表

树的类型

二叉树:完美二叉树、完全二叉树、完满二叉树

AVL树、红黑树、B树、B+树

树的遍历

准备了一颗以上的一棵普通的树

// 使用 Object 来实现树结构
type Tree = {
	value: string
	children: Tree[]
}

const tree: Tree = {
	value: 'a',
	children: [
		{
			value: 'b',
			children: [
				{
					value: 'd',
					children: []
				},
				{
					value: 'e',
					children: []
				}
			]
		},
		{
			value: 'c',
			children: [
				{
					value: 'f',
					children: []
				},
				{
					value: 'g',
					children: []
				}
			]
		}
	]
}
深度遍历

一直往树的底部去遍历,尽可能深的搜索树的分支

image-20201121114859937

按照上图的顺序就是 1 -> 2 -> 3 -> 4 -> 5 -> 6 -> 7

// 使用上述的常量 tree
// 递归版
// 树的深度遍历
// Tree 为 type, tree 是数据结构
import { Tree, tree } from './tree'

// 对树的结构按顺序进行遍历
const dft = (tree: Tree) => {
	console.log(tree.value)
	tree.children.forEach(dft)
}

dft(tree)

// a -> b -> d -> e -> c -> f -> g
广度遍历

先访问离根节点最近的结点

按照上图的顺序就是 1 -> 2 -> 3 -> 4 -> 5 -> 6 -> 7

// 使用上述的常量 tree
// 广度遍历
import { Tree, tree } from './tree'

const gft = (tree: Tree) => {
  // 使用队列数据接口
  // 先把头结点推入队列
  // 弹出头结点,然后遍历子节点
  // 子节点的头结点也推入队列中,以此类推
	const q = [tree]
	while (q.length) {
		// 弹出队列首项目
		const node = q.shift()
		if (!node) return
		console.log(node.value)
		q.push(...node.children)
	}
}

gft(tree)
// a -> b -> c -> d -> e -> f -> g

二叉树

树中每个节点最多只能有两个子节点

这也算是一棵二叉树

Object 表达式

type BTree = {
	value: string
	left?: BTree
	right?: BTree
}

const Btree: BTree = {
	value: 'a',
	left: {
		value: 'b',
		left: {
			value: 'd'
		},
		right: {
			value: 'e'
		}
	},
	right: {
		value: 'c',
		left: {
			value: 'f'
		},
		right: {
			value: 'g'
		}
	}
}

二叉树的遍历

二叉树遍历有三种遍历方法:先序遍历,中序遍历,后序遍历

先序遍历(递归)

遍历步骤

  1. 访问根节点
  2. 对根节点的左子树进行先序遍历
  3. 对根节点的右子树进行先序遍历

每个整体的子树的先序遍历顺序如上图所示

上面的二叉树先序遍历结果为:a -> b -> d -> e -> c -> f -> g

import { Btree, BTree } from './tree'

const preorder = (tree: BTree) => {
	console.log(tree.value)
	tree.left && preorder(tree.left)
	tree.right && preorder(tree.right)
}

preorder(Btree)
中序遍历(递归)

遍历步骤

  1. 对根节点的左子树进行中序遍历
  2. 访问根节点
  3. 对根节点的右子树进行中序遍历

每个整体的子树的中序遍历顺序如上图所示

上面的二叉树先序遍历结果为:d -> b -> e -> a -> f -> c -> g

import { Btree, BTree } from './tree'

const inorder = (tree: BTree) => {
  tree.left && inorder(tree.left)
  console.log(tree.value)
  tree.right && inorder(tree.right)
}

inorder(Btree)
后序遍历(递归)

遍历步骤

  1. 对根节点的左子树进行后序遍历

  2. 对根节点的右子树进行后序遍历

  3. 访问根节点

    每个整体的子树的中序遍历顺序如上图所示

上面的二叉树先序遍历结果为:d -> e -> b -> f -> g -> c -> a

import { Btree, BTree } from './tree'

const postorder = (tree: BTree) => {
	tree.left && postorder(tree.left)
	tree.right && postorder(tree.right)
	console.log(tree.value)
}

postorder(Btree)
先序遍历(非递归)

思路: 借助栈实现

const preorder = (tree: BTree) => {
	const stack = [tree]
	while (stack.length) {
		const node = stack.pop()
		if (!node) break
		console.log(node.value)
    // 借助栈 后进先出 的特性
		if (node.right) stack.push(node.right)
		if (node.left) stack.push(node.left)
	}
}
中序遍历(非递归)

思路:

借助栈实现,每碰到一个节点就收集一次左节点并压入栈中,直到最后一个左节点。

然后开始出栈,再对右子节点进行收集一次

const inorder = (tree: BTree) => {
	// 先搜集所有的左子结点(包含根结点)
	const stack: BTree[] = []
	let p: BTree | null = tree
	while (stack.length || !!p) {
		// 每次都收集一次左结点
		while (p) {
			stack.push(p)
			p = p.left ? p.left : null
		}
		const node = stack.pop()
		if (!node) break
		console.log(node.value)
		p = node.right ? node.right : null
	}
}
后序遍历(非递归)

思路: 将先序遍历翻转

const postorder = (tree: BTree) => {
	const stack = [tree]
	const outputStack = []
	while (stack.length) {
		const node = stack.pop()
		if (!node) break
		outputStack.push(node)
		if (node.left) stack.push(node.left)
		if (node.right) stack.push(node.right)
	}
	while (outputStack.length) {
		const node = outputStack.pop()
		if (!node) break
		console.log(node.value)
	}
}
二叉树的最大深度(练习)

Leetcode.101

/**
 * 二叉树的最大深度
 * 使用树形结构的深度遍历
 * 使用变量保存最大深度
 */
function maxDepth(root: TreeNode | null): number {
	let max = 0
	if (!root) return max

	// 深度遍历二叉树
	const dft = (root: TreeNode, level: number) => {
		if (!root) return
		if (!root.left && !root.right) {
			max = Math.max(max, level)
		}
		root.left && dft(root.left, level + 1)
		root.right && dft(root.right, level + 1)
	}
	dft(root, 1)
	return max
}
二叉树的最小深度(练习)

Leetcode.111

/**
 * 推荐使用广度遍历,而不使用深度遍历。
 * 广度遍历可以减少遍历的次数,更快的发现叶子节点
 * 遇到叶子节点则返回
 */
function minDepth(root: TreeNode | null): number {
	if (!root) return 0
	let min = 1
	const queue: [TreeNode, number][] = [[root, min]]
	while (queue.length) {
		const [node, level] = queue.shift()!
		if (!node.left && !node.right) return (min = level)
		if (node.left) queue.push([node.left, level + 1])
		if (node.right) queue.push([node.right, level + 1])
	}
	return min
}
二叉树的层序遍历(练习)

Leetcode.102

/**
 * 01
 * 使用广度遍历
 * 找出对应的子节点和层级,按照层级往数组的推入
 */
function levelOrder(root: TreeNode | null): number[][] {
	if (!root) return []
	const q: [TreeNode, number][] = [[root, 0]]
	const levelNodeList: [number][] = []
	while (q.length) {
		const [node, level] = q.shift()!
		if (levelNodeList[level]) {
			levelNodeList[level].push(node.val)
		} else {
			levelNodeList[level] = [node.val]
		}
		// 推入新节点
		if (node.left) q.push([node.left, level + 1])
		if (node.right) q.push([node.right, level + 1])
	}
	return levelNodeList
}

/**
 * 02
 * 使用广度遍历
 * 区分新节点与老节点(两者都是同一层级的节点)
 * 时间复杂度 (O)n : 全遍历树的所有节点
 * 空间复杂度(O)n : 使用了递归
 */
function levelOrder(root: TreeNode | null): number[][] {
	if (!root) return []
	const q = [root]
	const res: Array<number[]> = []
	while (q.length) {
		// 获取队列的长度
		let len = q.length
		res.push([])
		while (len--) {
			const node = q.shift()!
			res[res.length - 1].push(node.val)
			// 推入新节点
			if (node.left) q.push(node.left)
			if (node.right) q.push(node.right)
		}
	}
	return res
}

路径总和(练习)

Leetcode.112

/**
 * 采用深度遍历
 * 遇到叶子节点则进行判断总和是否与期望值相等
 * 时间复杂度 (O)n : 全遍历树的所有节点
 * 空间复杂度(O)n : 使用了递归
 */
function hasPathSum(root: TreeNode | null, sum: number): boolean {
	if (!root) return false
	let res = false
	const dft = (root: TreeNode, value: number) => {
		if (!root.left && !root.right && value === sum) {
			res = true
		}
		if (root.left) dft(root.left, root.left.val + value)
		if (root.right) dft(root.right, root.right.val + value)
	}
	dft(root, root.val)
	return res
}
遍历 JSON 对象 (练习)
const json = {
	a: {
		b: [1, 2, 3],
		c: {
			name: 'hello',
			val: 'world'
		}
	},
	d: {
		color: ['red', 'green', 'blue']
	}
}
// 凡科面试题 找出来做一下
// 拷贝 toString 方法
const checkType = Function.prototype.call.bind(Object.prototype.toString)
const typeAbout = (data: any) => {
	return (checkType(data) as string).substring(8).replace(']', '')
}

const jsonDfs = (n: any, path: string) => {
	console.log(n, path)
	debugger
	if (typeAbout(n) !== 'Object') return
	Reflect.ownKeys(n).forEach(key => {
		path += `.${String(key)}`
		jsonDfs(Reflect.get(n, key), path)
	})
}

jsonDfs(json, 'json')
后台管理的侧边栏菜单

Vue 可采用深度遍历 router 菜单

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值