文章内容主要为小册《程序员的必修课》的学习笔记以及个人理解,仅供个人学习使用。详细内容请支持正版小册。
不同的业务场景,适用不同的技术。运用合理的数据结构,降低时空复杂度,约等于成功了一半。
数据结构可以分为两大类:
- 线性数据结构:数据元素之间的关系是一对一的。
- 非线性数据结构:数据元素之间的关系不是一对一的。
线性数据结构
- 顺序表:紧密相邻。便于查找元素,不便于插入和删除元素。
- 链表:便于插入和删除,不便于查找
- 栈:FILO 先进后出,历史记录,撤销回退
- 队列:FIFO 先进先出,上传、下载队列
非线性数据结构
- 数:树是一对多的数据结构。适合有层级关系的场景。比如组织架构、目录
- 图:图是多对多的数据结构。适合没有层级的网状关系。比如通讯录,朋友圈好友信息
顺序表
class ArrayList {
private arr: number[] = new Array(10).fill(0);
private curIndex: number = -1;
public put(num: number): void {
if (++this.curIndex >= this.arr.length) {
throw new Error('Array index out of bounds');
}
this.arr[this.curIndex] = num;
}
public get(index: number): number {
if (index < 0 || index > this.curIndex) {
throw new Error('Array index out of bounds');
}
return this.arr[index];
}
public add(num: number, index: number): void {
for (let i = this.curIndex; i >= index; i--) {
this.arr[i + 1] = this.arr[i];
}
this.arr[index] = num;
this.curIndex++;
}
public remove(index: number): void {
for (let i = index; i < this.curIndex; i++) {
this.arr[i] = this.arr[i + 1];
}
this.curIndex--;
}
}
const list = new ArrayList();
list.put(10);
list.put(20);
list.put(30);
console.log(list);
console.log(list.get(0));
console.log(list.get(2));
list.add(15, 1);
console.log(list);
console.log(list.get(1));
list.remove(1);
console.log(list.get(1));
链表
// 定义元素Node
class Node {
value: number;
next: Node | null;
constructor(value: number, next: Node | null = null) {
this.value = value;
this.next = next;
}
}
class LinkedList {
private first: Node | null;
constructor() {
this.first = null;
}
put(num: number): void {
const node = new Node(num, null);
if (this.first == null) {
this.first = node;
} else {
let curNode = this.first;
while (curNode.next != null) {
curNode = curNode.next;
}
curNode.next = node;
}
}
get(index: number): number {
let i = index;
let curNode = this.first;
while (i > 0 && curNode !== null) {
curNode = curNode.next;
i--;
}
if (curNode === null) {
throw new Error('Index out of bounds');
}
return curNode.value;
}
add(num: number, index: number): void {
let node = this.first;
while (--index > 0 && node !== null) node = node.next;
if (node === null) {
throw new Error('Index out of bounds');
}
const newNode = new Node(num);
newNode.next = node.next;
node.next = newNode;
}
remove(index: number): void {
if (index === 0) {
if (this.first === null) {
throw new Error('List is empty');
}
this.first = this.first.next;
return;
}
let node = this.first;
while (--index > 0 && node !== null) node = node.next;
if (node === null || node.next === null) {
throw new Error('Index out of bounds');
}
node.next = node.next.next;
}
}
const linkedList = new LinkedList();
linkedList.put(3);
linkedList.put(5);
linkedList.put(7);
linkedList.put(9);
console.log('linkedList => ', linkedList);
栈
遵循后进先出(LIFO)的原则,非常常见,这里就不举例了
队列
先进先出,也是非常常见的结构,一般用数组去实现,也可以用链表,之前有一篇文章介绍过一个小而美的库,大家可以去看一下yocto-queue源码解读:链表、迭代器与高效队列