链表
相对于数组, 链表有一些优点:
- 内存空间不是比是连续的. 可以充分利用计算机的内存. 实现灵活的内存动态管理.
- 链表不必在创建时就确定大小, 并且大小可以无限的延伸下去.
- 链表在插入和删除数据时, 时间复杂度可以达到O(1). 相对数组效率高很多.
相对于数组, 链表有一些缺点:
- 链表访问任何一个位置的元素时, 都需要从头开始访问.(无法跳过第一个元素访问任何一个元素).
- 无法通过下标直接访问元素, 需要从头一个个访问, 直到找到对应的问题
单项链表的实现
//封装节点类
class Node {
constructor(data) {
this.data = data;
this.next = null;
}
}
//封装链表
class LinkedList {
constructor() {
//头指针为null
this.head = null;
this.length = 0;
}
//添加节点
appen(data) {
//创建节点
let newNode = new Node(data);
//判断链表中是否有节点
if (this.length == 0) {
this.head = newNode;
} else {
//定义指针,从头开始遍历
let current = this.head;
//遍历到next指向null的节点,然后添加节点
while (current.next) {
current = current.next;
}
current.next = newNode;
}
this.length += 1;
}
//打印链表
toString() {
let current = this.head;
let listString = "";
while (current) {
listString += current.data + " ";
current = current.next;
}
return listString;
}
//插入方法
insert(position, data) {
//创建节点
let newNode = new Node(data);
//判断postion是否越界
if (position < 0 || position > this.length) {
return false;
}
//是否插入到的是0位置
if (position == 0) {
newNode.next = this.head;
this.head = newNode;
} else {
let index = 0;
let current = this.head;
let previous = null;
while (index++ < position) {
previous = current;
current = current.next;
}
newNode.next = current;
previous.next = newNode;
}
this.length += 1;
return true;
}
//获取指定节点的元素
get(position) {
//判断越界
if (position < 0 || position > this.length - 1) return null;
//查找节点
let index = 0;
let current = this.head;
while (index++ < position) {
current = current.next;
}
return current.data;
}
//查找索引
indexOf(data) {
let index = 0;
let current = this.head;
let flag = false;
while (index < this.length) {
if (data == current.data) {
return index;
flag = true;
}
index++;
current = current.next;
}
if (!flag) {
return -1;
}
}
//更新数据
upData(position, data) {
//判断越界
if (position < 0 || position > this.length - 1) return false;
//查找节点
let index = 0;
let current = this.head;
while (index++ < position) {
current = current.next;
}
current.data = data;
return true;
}
//移除特定位置的节点
removeAt(position) {
if (position < 0 || position > this.length - 1) 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;
return current.data;
}
//根据data删除相应的节点
remove(data) {
// let previous = null;
// let current = this.head;
// while (current) {
// if (data == current.data) {
// previous.next = current.next;
// return current.data;
// }
// previous = current;
// current = current.next;
// }
// if (!current) {
// return false;
// }
//直接使用封装好的方法
let index = this.indexOf(data);
return this.removeAt(index);
}
isEmpty() {
return this.length == 0;
}
size() {
return this.length;
}
}
//创建链表
let nodeList = new LinkedList();
nodeList.appen("a");
nodeList.appen("b");
nodeList.appen("d");
nodeList.appen("e");
alert(nodeList.isEmpty());
alert(nodeList.size());
双向链表
由于单项链表我们只能从一个方向遍历链表,如果我们向在遍历的过程中向前移动指针,这个就无法实现了。因此出现了双项链表,我们可以从头到尾或者从尾到头的进行遍历。遍历过程中指针可以前后移动,方便我们获取值。
缺点:
- 双项链表占用的内存空间较大。
- 实现双项链表比较繁琐。
双项链表的实现
//节点类
class Node {
constructor(data) {
this.prev = null;
this.next = null;
this.data = data;
}
}
//双项链表类
class doublyLinkedList {
constructor() {
//头指针
this.head = null;
//尾指针
this.tail = null;
//链表长度
this.length = 0;
}
//append方法
append(data) {
const newNode = new Node(data);
//判断是否是第一个节点
if (this.length == 0) {
this.head = newNode;
this.tail = newNode;
} else {
this.tail.next = newNode;
newNode.prev = this.tail;
this.tail = newNode;
}
//length+1
this.length += 1;
}
//插入节点
insert(position, data) {
//判断是否越界
if (position < 0 || position > this.length) return false;
//创建新的节点
const newNode = new Node(data);
//判断是否有元素
if (this.length == 0) {
this.head = newNode;
this.tail = newNode;
} else {
//判断是否是插入是不是第一个位置
if (position == 0) {
newNode.next = this.head;
this.head.prev = newNode;
this.head = newNode;
} else {
let index = 0;
let current = this.head;
let previous = null;
//找到要插入的位置
while (index++ < position) {
previous = current;
current = current.next;
}
//如果是添加到最后
previous.next = newNode;
newNode.prev = previous;
if (position == this.length) {
newNode.next = null;
this.tail = newNode;
} else {
//进行链接
newNode.next = current;
current.prev = newNode;
//修改成功,返回true
}
}
}
this.length += 1;
return true;
}
//获取指定节点的值
get(position) {
//越界判断
if (position < 0 || position >= this.length) return null;
if (position <= this.length / 2) {
let index = 0;
let current = this.head;
while (index++ < position) {
current = current.next;
}
return current.data;
} else {
let index = this.length - 1;
let current = this.tail;
while (index-- > position) {
current = current.prev;
}
return current.data;
}
}
//查找节点所在的位置
indexOf(data) {
let index = 0;
let current = this.head;
while (current) {
if (current.data == data) {
return index;
}
current = current.next;
index += 1;
}
return -1;
}
//修改链表的某一个节点
update(position, data) {
if (position < 0 || position >= this.length) return false;
if (position <= this.length / 2) {
let index = 0;
let current = this.head;
while (index++ < position) {
current = current.next;
}
current.data = data;
} else {
let index = this.length - 1;
let current = this.tail;
while (index-- > position) {
current = current.prev;
}
current.data = data;
}
return true;
}
//删除下标对应节点
removeAt(position) {
if (position < 0 || position >= this.length) return false;
//判断是否只有一个节点
let current = this.head;
if (this.length == 1) {
this.head = null;
this.tail = null;
} else {
//删除第一个节点
if (position == 0) {
this.head.next.prev = null;
this.head = this.head.next;
} else if (position == this.length - 1) {
//删除最后一个节点
current = this.tail;
this.tail.prev.next = null;
this.tail = this.tail.prev;
} else {
let index = 0;
while (index++ < position) {
current = current.next;
}
current.prev.next = current.next;
current.next.prev = current.prev;
}
}
this.length -= 1;
return current.data;
}
//删除元素
remove(data) {
let index = this.indexOf(data);
return this.removeAt(index);
}
//输出
toString() {
return this.backwardString();
}
//向后遍历
backwardString() {
//遍历到的元素,起初指向this.head,即第一个元素
let current = this.head;
let resultString = "";
while (current) {
resultString += current.data + " ";
current = current.next;
}
return resultString;
}
//向前遍历
forwardString() {
let current = this.tail;
let resultString = "";
while (current) {
resultString += current.data + " ";
current = current.prev;
}
return resultString;
}
//判断链表是否为空
isEmpty() {
return this.length == 0 ? true : false;
}
//获取链表长度
size() {
return this.length;
}
//获取链表第一个元素
getHead() {
return this.head.data;
}
//获取链表最后一个元素
getTail() {
return this.tail.data;
}
}
let DoublyList = new doublyLinkedList();
DoublyList.insert(0, "foo");
DoublyList.append("aaa");
DoublyList.append("bbb");
DoublyList.append("ccc");
DoublyList.append("ddd");
DoublyList.update(4, "fdfd");
alert(DoublyList.toString());
alert(DoublyList.getHead());
alert(DoublyList.getTail());