基础数据结构
数据结构:数据的存储方式。
- 数据:信息的载体,是描述客观事物属性的数、字符及所有能输入到计算机中并被计算机程序识别和处理的符号的集合。
- 数据对象:具有相同性质的数据元素的集合,是数据的一个子集。
- 数据元素:数据的基本单位,通常作为一个整体进行考虑和处理。
- 数据项:构成数据元素的不可分割的最小单位。
数据结构的三要素
逻辑结构:分为线性结构、集合、树形结构、图状结构。集合、树形结构、图状结构统称为非线性结构。
物理结构(存储结构):顺序存储、链式存储、索引存储、散列/哈希存储。
栈与队列
执行顺序:栈 - 先入后出, 队列 - 先入先出。
class Stack {
constructor() {
this.items = [];
}
push(element) {
this.items.push(element);
}
pop() {
return this.items.pop();
}
peek() {
return this.items[this.items.length - 1];
}
isEmpty() {
return this.items.length === 0;
}
clear() {
this.items = [];
}
size() {
return this.items.length;
}
}
算法流程
1. 需要什么样的数据结构、满足模型的数据 —— 构造变量 & 常量 2. 运行方式:简单的条件执行、遍历、递归 —— 算法主体结构 3. 确定输入输出:确定流程
const isValid = function(s) {
const stack = new Stack();
const map = {
'}': '{',
']': '[',
')': '('
};
for(let i = 0; i < s.length; i++) {
const char = s[i];
stack.push(char);
if(stack.size < 2)
continue;
const theLastOne = stack[stack.size - 1];
const theLastTwo = stack[stack.size - 2];
if(map[theLastOne] === theLastTwo) {
stack.pop();
stack.pop();
}
}
return stack.size === 0;
}
数组和链表
- 查找:数组连续、效率高。
- 数组可以迅速定位到数组中某一个节点的位置。
- 链表则通过前一个元素指向下一个元素,需要前后依赖顺序查找,效率较低。
- 插入:
- 数组插入元素后,后序所有元素的索引都会受到影响和改变。
- 链表由于其指向属性的原因,只要改变前一项和当前被插入项的指向即可完成插入。
class Node {
constructor(element) {
this.element = element;
this.next = null;
}
}
class LinkedList {
constructor() {
this.length = 0;
this.head = null;
}
getElementAt(position) {
if(position < 0 || position >= this.length)
return null;
let _current = this.head;
for(let i = 0; i < position; i++) {
_current = _current.next;
}
return _current;
}
append(element) {
let _node = new Node(element);
if(this.head === null) {
this.head = _node;
}else {
let _current = this.getElementAt(this.length - 1);
_current.next = _node;
}
this.length++;
}
insert (position, element) {
if(position < 0 || position > this.length)
return false;
let _node = new Node(element);
if(position === 0) {
_node.next = this.head;
this.head = _node;
}else {
let _previous = this.getElementAt(position - 1);
_node.next = _previous.next;
_previous.next = _node;
}
this.length++;
return true;
}
removeAt (position) {
if(position < 0 || position > this.length)
return false;
let _current = this.head;
if(position === 0) {
this.head = _current.next;
}else {
let _previous = this.getElementAt(position - 1);
_current = _previous.next;
_previous.next = _current.next;
}
this.length--;
return _current.element;
}
indexOf(element) {
let _current = this.head;
for(let i = 0; i < this.length; i++) {
if(_current.element === element)
return i;
_current = _current.next;
}
return -1;
}
}
哈希表
const MAP = {
'I': 1,
'V': 5,
'X': 10,
'L': 50,
'C': 100
}
const romanToInt = function(s) {
let len = s.length;
let max = 0;
let res = 0;
while(len--) {
let num = MAP[s[len]];
if(max > num) {
res -= num;
continue;
}
max = num;
res += num;
}
return res;
}
树结构
前序遍历(中左右)、中序遍历(左中右)、后序遍历 (左右中)
class Node {
constructor(node) {
this.left = node.left;
this.right = node.right;
this.value = node.value;
}
}
const PreOrder = function(node) {
if (node !== null) {
console.log(node.value);
PreOrder(node.left);
PreOrder(node.right);
}
}
const InOrder = function(node) {
if (node !== null) {
InOrder(node.left);
console.log(node.value);
InOrder(node.right);
}
}
const PostOrder = function(node) {
if (node !== null) {
PostOrder(node.left);
PostOrder(node.right);
console.log(node.value);
}
}
function findNode(root, value) {
if(root === undefined || root === null) {
return null;
}
if(root.value > value) {
return findNode(root.leftNode, value);
}
if(root.value < value) {
return findNode(root.rightNode, value);
}
if(root.value === value) {
return root;
}
}
数据结构和算法的关系
算法复杂度概念
时间复杂度
指执行算法所需要的计算工作量。
- 循环次数最多的代码块
- 最大值原则:多个循环,总复杂度等于最大的代码块的复杂度
- 乘法原则:嵌套的代码复杂度等于嵌套内外代码复杂度乘积
但凡涉及到时间复杂度的问题 => 单层执行、遍历循环、等比变化、委托复合。
空间复杂度
指算法需要消耗的内存空间。
- 常量
- 线性增长O(N)
- log增长
复杂度比较
常数阶O(1) > 对数阶O(logN) > 线性阶O(n) > 线性对数阶O(nlogN) > 平方阶 O(nn) > 立方阶 O(nn*n) > k次方阶 O(n^k)
所以一个好的算法:速度快,存储空间少。
具体算法技巧与概念
分治法D&C
工作原理:
- 找出基线条件
- 不断将问题分解 —— 基线保持一致
- 直到被拆解的问题最终复合基线条件
const quickSort = function(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));
}
贪婪Greedy
获取利益最大化,始终查找最大项目,尽可能快速满足需求。
const maxSubArray = function(nums) {
let ans = nums[0];
let sum = 0;
for(const num of nums) {
if(sum > 0) {
sum += num;
}else {
sum = num;
}
ans = Math.max(ans, sum);
}
return ans;
}
动态规划DP
可划分职责领域,下一步规划。
const fib = function(n) {
if(n < 2) {
return n;
}
let pre = 0, next = 0, result = 1;
for(let i = 2; i < n; i++) {
pre = next;
next = result;
result = pre + next;
}
return result;
}
图Graph
构成:边集合和顶点集合。 分类:有向图、无向图、构造图。
class Graph {
constructor(v) {
this.vertices = v;
this.edges = 0;
this.arr = [];
for(let i = 0; i < this.vertices; i++) {
this.arr[i] = [];
}
}
addEdge(v, w) {
this.arr[v].push(w);
this.arr[w].push(v);
this.edges++;
}
showGraph() {
for(let i = 0; i < this.vertices; i++) {
let str = i + '=>';
for(let j = 0; j < this.vertices; j++) {
if (this.arr[i][j] !== undefined) {
str += this.arr[i][j] + '';
}
}
console.log(str);
}
}
}
constructor() {
this.marked = [];
for(let i = 0; i < this.vertices; i++) {
this.marked[i] = false;
}
}
dfs(v) {
this.marked[v] = true;
if(this.arr[v] !== undefined) {
console.log('arrived' + v);
}
(this.arr[v] || []).forEach(w => {
if(!this.marked[w]) {
this.dfs(w);
}
})
}
bfs(s) {
let queue = [];
this.marked[s] = true;
queue.push(s);
while(queue.length > 0) {
let v = queue.shift();
if(v !== undefined) {
console.log('arrived' + v);
}
(this.arr[v] || []).forEach(w => {
if(!this.marked[w]) {
this.marked[w] = true;
queue.push(w);
}
})
}
}
|