js数据结构

什么是数据结构:数据结构是计算机存储、组织数据的方式。数据结构是指相互之间存在一种或多种特定关系的数据元素的集合。通常情况下,精心选择的数据结构可以带来更高的运行或者存储效率。数据结构往往同高效的检索算法和索引技术有关;

栈(Stack)

什么是栈:栈是一种高效的数据结构(后进先出(LIFO)原则的有序集合),因为数据只能在栈顶添加或删除,所以这样的操作很快,而且容易实现。

场景:编程语言中的编译器、计算机内存存储变量和方法调用,浏览器的后退功能等等;

Stack包含以下方法

  • push(e):将新添加的元素添加至堆栈的顶部
  • pop():删除栈顶的元素,同时返回已删除的元素
  • peek():返回堆栈的顶部元素
  • isEmpty():判断堆栈是否为空,如果为空返回true
  • clear(): 清空堆栈所有的元素
  • size(): 返回堆栈元素的数量,类似数组的长度
  • toArray():以数组的形式返回堆栈的元素
  • toString(): 以字符串的形式输出堆栈的内容;

由于数组是有序数组,如果存储大数据内容过多的话,会消耗更多的计算机内存,算法的复杂度就会增加,为了解决此类问题,建议使用对象的形式;

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
export default class Stack {
constructor() {
this.count = 0;
this.items = {};
}
push(element) {
this.items[this.count] = element;
this.count++;
}
pop() {
if (this.isEmpty()) {
return undefined;
}
this.count--;
const result = this.items[this.count];
delete this.items[this.count];
return result;
}
peek() {
if (this.isEmpty()) {
return undefined;
}
return this.items[this.count - 1];
}
isEmpty() {
return this.count === 0;
}
size() {
return this.count;
}
clear() {
/* while (!this.isEmpty()) {
this.pop();
} */
this.items = {};
this.count = 0;
}
toString() {
if (this.isEmpty()) {
return '';
}
let objString = `${this.items[0]}`;
for (let i = 1; i < this.count; i++) {
objString = `${objString},${this.items[i]}`;
}
return objString;
}
}

以上方法在Stack类中声明的items和count属性是不受保护的,可以使用symbol数据类型作为对象的属性具有私有性的特点,改变以上属性;

1
2
3
4
5
6
7
8
9
10
11
const _items = Symbol('stack')
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}
size(){return this[_items].length}
clear(){this[_items] = []}
toString(){return this[_items].toString()}
}

实际应用举例
实现一个十进制转换二进制的功能,在与计算机进行通信必须使用二进制的功能,如果需要转换2进制需要将转换的数字除以2,再将结果除以2,如此循环,直到结果为0为止;

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
function decimalToBinary(decNumber){
const remStack = new Stack()
let number = decNumber
let rem;
let binaryString = ''
while(number > 0){
rem = Math.floor(number % 2)
remStack.push(rem)
number = Math.floor(number/2)
}
while(!remStack.isEmpty()){ // 如果不为空则会一直循环;
binaryString += remStack.pop().toString()
// 将数取出来并添加进去;
}
return binaryString
}

链表(Linked List)

链表是一个线性结构,同时也是一个天然的递归结构,链表结构可以充分利用计算机内存空间,实现灵活的内存动态管理,但是链表失去了数组随机读取的优点,同时链表由于增加了结点的指针域,空间开销比较大;

为何要使用链表:因为数组有缺陷,增删元素时往往需要移动元素,而链表在内存中的放置并不是连续的,元素通过next属性指向下个元素,所以链表增删元素,不需要移动元素,只需要更改next的指向即可;

使用场景:在javascript中,最重要的链:作用域链和原型链;

链表的创建:

首先创建一个用来保存链表里的数据

1
2
3
4
5
6
7
8
9
/**
* Node用来表示节点
* element 用来保存节点上的数据;
* next 用来保存指向下一个节点的链接;
*/
function Node(element){
this.element = element;
this.next = null
}

链表的方法:

  • append(element):向链表尾部添加一个新的元素
  • insert(position,element):向链表特定位置插入元素
  • remove(element): 从链表移除一项
  • indexOf(element): 返回链表中某元素的索引,如果没有返回-1
  • removeAt(position):从特定位置移除一项
  • isEmpty(): 判断链表是否为空,如果为空返回true
  • size(): 返回链表包含的元素个数
  • toString():重写继承Object类的tostring方法,因为我们使用了Node类;