一维数据结构(线性数据结构)
💡 Tips:操作系统小知识:通过偏移查询数据性能最好。
数组的特性:
- 存储在物理空间是连续的。
- 底层的数组长度是不可变的。
- 数组的变量,指向数组的第一个元素的位置。
优点:查询性能好。
缺点:
- 空间必须是连续的,当数组空间较大,且当系统中空间碎片较多的时候,容易存放不下。
- 长度是固定的,数组是难以被添加(可能需要扩容数组大小)和删除(可能需要将所删除元素位置后面的所有元素往前移动)的
优化:
- 创建数组时,在知道数组长度的情况下,使用new Array(10)的方式来固定数组的长度
数组总结:
- 数组的内存存储是连续的,受空间碎片的影响,数组内存较大的时候,容易存不下
- 数组查询性能较好
- 数组的受固定长度的影响,新增和删除的性能较差
链表(Linked-list)
💡 Tips:
链表的特点:
- 空间是不连续的
- 每存一个值,就会多开销一个引用空间
优点:
- 只要内存够大,就能存的下,不受空间碎片的影响
- 链表的删除和添加比较容易
缺点:
- 查询速度慢(查询某个位置)
- 每个创建的节点都需要创建一个next指向,浪费空间
链表总结:
- 链表在内存中存储不是连续的,所以不受内存碎片的影响
- 链表查询速度较慢(需从表头开始查询)
- 链表新增和删除的性能较好
链表基础操作示例:
class node {
value: any
next?: node | null
constructor(value: any, next: node | null = null) {
this.value = value;
this.next = next;
}
}
/**
* 1.初始化链表
* 2.打印链表所有节点
* 3.链表插入到某个节点之前
* 4.链表插入到某个节点之后
* 5.链表删除某个节点
* 6.链表查找某个节点
*/
/**
* 链表
*/
class LinkedList {
private head: node
/**
* 初始化链表
* @param value
* @param next
*/
constructor(value: any, next: node | null) {
this.head = new node(value, next);
}
/**
* 打印链表所有节点
* @returns void
*/
traverse(): void {
let root = this.head;
console.log(root.value);
while (root.next) {
root = root.next;
console.log(root.value);
}
}
/**
* 根据节点值来查询节点
* @param value
* @returns 返回查询出的节点
*/
search(value: any): node {
if (!this.head) return;
let root = this.head;
while (root) {
if (root.value === value) {
return root;
}
root = root.next;
}
return root;
}
/**
* 删除链表第一个节点
* @returns 删除删除的节点
*/
shift(): node {
const cur = this.head;
this.head = this.head.next
return cur
}
/**
* 删除链表最后一个节点
* @returns 返回删除的节点
*/
pop(): node {
let pre = null;
let cur = this.head;
while (cur && cur.next) {
pre = cur;
cur = cur.next;
}
pre.next = null;
return pre;
}
/**
* 获取最后一个节点
* @returns 返回最后一个节点
*/
private getLastNode(): node {
let cur = this.head;
while (cur.next) {
cur = cur.next;
}
return cur
}
/**
* 插入一个节点到链表最后
* @param value
* @returns 返回添加的节点
*/
push(value: any): node {
const newNode = new node(value);
let cur = this.getLastNode();
cur.next = newNode;
return cur;
}
/**
* 在链表头部插入一个节点
* @param value
* @returns 返回新添加的节点
*/
unshift(value: any): node {
const newNode = new node(value)
newNode.next = this.head;
this.head = newNode
return newNode;
}
/**
* 插入一个节点
* @param insertNodeValue
* @param insertNodeAfter 插入到哪一个值之后
*/
insertAfter(insertNodeValue: any, insertNodeAfter: any) {
const newNode = new node(insertNodeValue)
let cur = this.head;
while (cur && cur.value !== insertNodeAfter) {
cur = cur.next;
}
if (cur) {
// 存储的是地址
let next = cur.next;
cur.next = newNode;
newNode.next = next;
}
}
/**
* 插入一个节点
* @param insertNodeValue
* @param insertNodeBefore 插入到哪一个值之后
*/
insertBefore(insertNodeValue: any, insertNodeBefore: any) {
const newNode = new node(insertNodeValue)
let cur = this.head;
let pre = null;
while (cur && cur.value !== insertNodeBefore) {
pre = cur;
cur = cur.next;
}
if (cur && !pre) {
// 这种情况可能是只有一个节点
this.unshift(insertNodeValue)
} else if (cur) {
// 存储的是地址
pre.next = newNode;
newNode.next = cur;
}
}
/**
* 删除对应值的节点(一次仅能删除一个)
* @param value
* @returns 返回删除的节点
*/
delete(value: any) {
let cur = this.head;
if (!cur) return;
// 删除第一个节点
if (cur && cur.value === value) {
this.head = cur.next;
return cur;
}
let pre = null;
while (cur.next && cur.value !== value) {
pre = cur;
cur = cur.next;
}
// 有所需删除的节点
if (cur) {
pre.next = cur.next;
}
return cur;
}
/**
* 链表逆序
*/
reserve() {
let pre = null;
let cur = this.head;
while (cur) {
let next = cur.next;
cur.next = pre;
pre = cur;
cur = next;
}
this.head = pre;
}
}
const LinkList = new LinkedList(1, null)
LinkList.push(2)
LinkList.push(3)
LinkList.push(4)
LinkList.push(5)
LinkList.insertBefore(6, 1)
LinkList.reserve()
LinkList.traverse();