JS数据结构(5)——单向链表
链表和数组的区别:
数组的优缺点:
- 数组是最常用的数据结构,它用来存储多个元素。
- 几乎每一种编程语言中都有默认实现数组结构,并且有很多关于数组的操作方法。
- 数组的修改和查找操作,时间复杂度低。
- 数组的创建通常需要申请一段连续的内存空间,并且大小是固定的,所以当当前的数组不能满足容量需求的时候,就需要扩容(一般情况下会申请一个更大的数组,比如说原数组的2倍,然后将原数组中的元素再复制过去),这对空间造成了大量浪费。
- 而且在数组开头或者中间插入数据的成本非常高,需要进行大量元素的位移。
- 虽然现在JavaScript的Array类方法已经可以很方便的使用,但是对空间和时间有很大的浪费,消耗程序的性能。
链表的优势:
- 要存储多个元素,除了数组另外一个选择就是链表。
- 但是不同于数组,链表中的元素在内存中不需要一定是连续的空间。
- 链表的每个元素是由一个存储元素本身和一个指向下一个元素的指针做成。
链表相对于数组的优势:
- 内存空间不需要是连续的,可以充分利用计算机的内存,实现灵活的动态管理、
- 链表在创建时不需要确定大小,它的大小可以无限的延伸下去。
- 链表在插入和删除数据时,时间复杂度可以达到O(1),相对数组效率高了很多。
链表相对于数组的劣势:
- 链表访问任何一个位置的元素,都必须从头开始访问。
- 链表无法通过下标值直接访问元素,需要从头开始一个一个访问,直到找到对应的元素。
什么是链表(Linked List)
- 链表和数组一样,都可以用于存储一系列的元素,但是链表和数组的实现机制完全不同。
- 链表是一系列的存储数据元素的单元通过指针连接起来而形成的,因此每个节点(node)都至少有两个域,一个域用来存储数据元素,另外一个域用来存放指向其他单元的指针。
- 链表的第一节点和最后一个节点,分别是链表的头节点(head)和尾节点,尾节点的特征是它的next引用为空(null)。链表中每个节点的next引用都相当于一个指针,指向另一个节点。
链表的结构:

链表结构的封装
- 代码思路:
- 我们需要封装一个 LinkedList 的类,用于表示链表结构。
- 在LinkedList类中,需要封装一个内部类用于表示每个节点信息(数据的指向下一个单元的指针)。
- 链表中我们还需要保存两个属性,一个是链表的长度,另一个是链表的第一个节点。
- 链表中常见的操作:
(1)append(data):向链表尾部添加一个新的节点。
(2)insert(position,data):向链表的指定位置插入一个新的节点。
(3)remove(element):从链表中移除数据为element的一项
(4)removeAt(position):从链表中移除指定位置的一项。
(5)update(position):修改某个位置的元素
(6)get(position):获取对应位置的元素
(7)indexOf(element):返回element在列表中的索引值,如果没有返回-1。
(8)isEmpty():如果链表中不包含任何元素,返回true,如果链表长度大于0则返回false。
(9)size():返回链表包含的元素个数,与length属性类似。
(10)toString():以String的方式输出链表中元素的值。
- 代码实现
function LinkedList() {
this.head = null;
function node(data) {
this.data = data;
this.next = null;
}
this.length = 0;
LinkedList.prototype.append = function(data) {
var newNode = new node(data);
if(this.length == 0)
this.head = newNode;
else {
var current = this.head;
while(current.next)
current = current.next;
current.next = newNode;
}
this.length++;
}
LinkedList.prototype.insert = function(position, data) {
if(position < 0 || position > this.length)
return false;
var newNode = new node(data);
if(position == 0){
newNode.next = this.head;
this.head = newNode;
}else {
var index = 0;
var current = this.head;
while(index < position - 1) {
current = current.next;
index++;
}
newNode.next = current.next;
current.next = newNode;
}
this.length++;
}
LinkedList.prototype.get = function(position) {
if(position < 0 || position >= this.length)
return null;
var current = this.head;
var index = 0;
while(index < position) {
index++;
current = current.next;
}
return current.data;
}
LinkedList.prototype.indexOf = function(element) {
var current = this.head;
var index = 0;
while(current.data !== element){
current = current.next;
index ++;
}
if(current.data === element)
return index;
return -1;
}
LinkedList.prototype.updata = function(position, element) {
if(position < 0 || position > this.length)
return null;
var current = this.head;
var index = 0 ;
while(index < position) {
index ++;
current = current.next;
}
current.data = element;
return true;
}
LinkedList.prototype.removeAt = function(position) {
var current = this.head;
if(position < 0 || position >= this.length) return null;
if(position === 0)
this.head = this.head.next;
else {
var index = 0;
while(index < position - 1) {
current = current.next;
index ++;
}
current.next = current.next.next;
}
this.length --;
return true;
}
LinkedList.prototype.remove = function(element) {
var position = this.indexOf(element);
return this.removeAt(position);
}
LinkedList.prototype.toString = function() {
var current = this.head;
var listString = "";
while(current){
listString += current.data + " ";
current = current.next;
}
return listString;
}
LinkedList.prototype.isEmpty = function() {
if(this.length === 0)
return true;
return false;
}
LinkedList.prototype.size = function() {
return this.length;
}
}
var list = new LinkedList();
list.append(111);
list.append(222);
console.log(list.toString());
list.insert(1, 333);
console.log(list.toString());
console.log(list.get(1));
console.log(list.indexOf(333));
console.log(list.updata(2,999));
console.log(list.toString());
console.log(list.removeAt(1));
console.log(list.toString());
list.append(444);
list.append(555);
list.append(666);
console.log(list.toString());
list.remove(444);
console.log(list.toString());
console.log(list.isEmpty());
console.log(list.size());