一、链表基础
- 优点
- 链表在内存中的存储空间不连续,可以灵活的利用存储空间
- 相对于数组存储空间必须是连续的一段,链表更为灵活
- 数组在头部增加/删除数据,效率最为低下,链表则不一样,时间复杂度为O(1)
- 数组空间需要拓展时,一般为先申请一块更大的连续的存储空间,并将原数组的数据进行拷贝
- 当在头部增加数据时,则原本的第一位及其后的数据都得往后挪动一位,效率比较低
- 缺点
- 链表无法像数组那样根据下标来快速定位到对应的元素,只能通过指针遍历从头一个一个查找
- 总结
- 当线性表的长度变化不大、易于确定其大小时,采用顺序表作为存储结构。
- 若线性表主要操作是查找。很少进行插入或删除操作时,采用顺序表作为存储结构。
- 对于频繁进行插入和删除的线性表,则应该使用链表作为存储结构。
二、实现代码
function LinkedList() {
this.length = 0;
this.head = null;
function Node(element) {
this.element = element;
this.next = null;
}
LinkedList.prototype.append = (element) => {
const node = new Node(element);
if (!this.head) {
this.head = node;
} else {
let current = this.head;
while (current.next) {
current = current.next;
}
current.next = node;
}
this.length += 1;
};
LinkedList.prototype.insert = (position, element) => {
if (position < 0 || position > this.length) return false;
const node = new Node(element);
if (position === 0) {
node.next = this.head;
this.head = node;
} else {
let current = this.head;
let previous = null;
let index = 0;
while (index++ < position) {
previous = current;
current = current.next;
}
node.next = current;
previous.next = node;
}
this.length += 1;
return true;
};
LinkedList.prototype.get = (position) => {
if (position < 0 || position >= this.length) return null;
let index = 0;
let current = this.head;
while (index++ < position) {
current = current.next;
}
return current.element;
};
LinkedList.prototype.indexOf = (element) => {
let current = this.head;
let index = 0;
while (current) {
if (current.element === element) {
return index;
}
current = current.next;
index++;
}
return -1;
};
LinkedList.prototype.update = (position, element) => {
if (position < 0 || position >= this.length) return false;
let index = 0;
let current = this.head;
while (index++ < position) {
current = current.next;
}
current.element = element;
return true;
};
LinkedList.prototype.removeAt = (position) => {
if (position < 0 || position >= this.length) return false;
let current = this.head;
if (position == 0) {
this.head = current.next;
} else {
let index = 0;
let previous = null;
while (index++ < position) {
previous = current;
current = current.next;
}
previous.next = current.next;
}
this.length -= 1;
};
LinkedList.prototype.remove = (element) => {
const position = this.indexOf(element);
return this.removeAt(position);
};
LinkedList.prototype.isEmpty = () => {
return this.length === 0;
};
LinkedList.prototype.size = () => {
return this.length;
};
LinkedList.prototype.toString = () => {
let resultString = "";
let current = this.head;
while (current) {
resultString += current.element + " ";
current = current.next;
}
return resultString;
};
}
const linkedList = new LinkedList();
linkedList.append("【1】我是第一个");
linkedList.append("【2】我是第二个");
linkedList.append("【3】我是第三个");
linkedList.insert(0, "【4】我是路过的");
linkedList.insert(2, "【5】我是插队的");
console.log("linkedList.size()", linkedList.size());
linkedList.insert(5, "【6】我是来排队的");
linkedList.update(5, "我更新咯");
linkedList.removeAt(5);
console.log("linkedList.toString()", linkedList.toString());
linkedList.remove("【3】我是第三个");
console.log("linkedList.toString()", linkedList.toString());