function DoublyLinkedList() {
this.head = null;
this.tail = null;
this.length = 0;
function Node(data) {
this.previous = null;
this.next = null;
this.data = data;
}
DoublyLinkedList.prototype.append = function (data) {
//创建新的节点
var newNode = new Node(data);
//判断是否为插入链表的第一个节点
if (this.length === 0) {
this.head = newNode;
this.tail = newNode;
} else {
//如果插入的元素不是链表的第一个节点
newNode.previous = this.tail;
this.tail.next = newNode;
this.tail = newNode;
}
this.length += 1;
}
DoublyLinkedList.prototype.forwardString = function () {
var current = this.tail;
var resultStr = '';
while (current) {
resultStr += current.data + ' ';
current = current.previous;
}
return resultStr;
}
DoublyLinkedList.prototype.backwardString = function () {
var current = this.head;
var resultStr = '';
while (current) {
resultStr += current.data + ' ';
current = current.next;
}
return resultStr;
}
DoublyLinkedList.prototype.toString = function () {
return this.backwardString();
}
DoublyLinkedList.prototype.insert = function (position, data) {
//判断越界
if (position < 0 || position > this.length) return false;
//创建新的节点
var newNode = new Node(data);
//如果当前链表是空链表
if (this.length === 0) {
this.head = newNode;
this.tail = newNode;
//下面的情况都是插入时链表不为空
} else if (position === 0) {
//如果插入的位置是索引为0,也就是第一个位置
newNode.next = this.head;
this.head.previous = newNode;
this.head = newNode;
} else if (position === this.length) {
//如果插入的位置是索引为this.length,也就是最后一个位置
newNode.previous = this.tail;
this.tail.next = newNode;
this.tail = newNode;
} else {
//如果插入的位置是索引为中间位置
var current = this.head;
var previous = null;
var count = 0;
while (count < position) {
//这样就通过循环找到了要插入的地方对应的元素current和它前一个元素previous
previous = current;
current = current.next;
count += 1;
}
newNode.previous = previous;
newNode.next = current;
current.previous = newNode;
previous.next = newNode
}
this.length += 1;
}
DoublyLinkedList.prototype.get = function (position) {
//越界判断
if (position < 0 || position >= this.length) return null;
//我们把整个链表分为2段,前半段和后半段,根据position的值和length/2的值的大小关系
//决定遍历的方向,这样提高性能
//如果position属于后半段,我们就从后往前遍历
//如果position属于前半段,我们就从前往后遍历
var middle = Math.floor(this.length/2);
//1.position属于前半段
if (position < middle) {
//箭头指向的是遍历的方向从前往后
console.log('---->');
var index = 0;
var current = this.head;
while (index < position) {
current = current.next;
index += 1;
}
} else {
//2.position属于后半段
//箭头指向的是遍历的方向从后往前
console.log('<----');
var index = this.length;
var current = this.tail;
while(index-1>position){
current = current.previous;
index -= 1;
}
}
return current.data;
}
DoublyLinkedList.prototype.indexOf = function(data){
var index = 0;
var current = this.head;
while(current){
if(current.data == data){
return index;
}
current = current.next;
index += 1;
}
return -1;
}
DoublyLinkedList.prototype.update = function(position,data){
//判断越界
if(position<0 || position>=this.length) return false;
//获取链表的中间值
var middle = Math.floor(this.length/2);
var current = null;
//1.position属于前半段
if(position<middle){
//从前往后遍历
var count = 0;
current = this.head;
while(count<position){
current = current.next;
count +=1;
}
} else {
//2.position属于后半段
var count = this.length;
current = this.tail;
while(count>position+1){
count -=1;
current = current.previous;
}
}
//更新data
current.data = data;
return true;
}
DoublyLinkedList.prototype.removeAt = function(position) {
if(position<0 || position>=this.length) return false;
//如果链表里面只有一个元素
if(this.length === 1){
this.head = null;
this.tail = null;
} else {
//链表里有多个元素,删除索引为0的元素
if(position === 0){
this.head.next.previous = null;
this.head = this.head.next;
} else if(position === this.length-1){
//链表里有多个元素,删除最后一个元素
this.tail = this.tail.previous
this.tail.next = null;
} else {
//链表里有多个元素,删除中间一个元素
var current = this.head;
var previous = null;
var count = 0;
//通过循环找到要删除的元素的索引current和它前一个元素previous
while(count<position){
previous = current;
current = current.next;
count += 1;
}
current.next.previous = previous;
previous.next = current.next;
current.next = null;
current.previous = null;
}
}
this.length -=1;
return true;
}
DoublyLinkedList.prototype.remove = function(data){
var index = this.indexOf(data);
this.removeAt(index);
}
}
//Test测试代码
var dllist = new DoublyLinkedList();
dllist.append('rabbit');
dllist.append('dog');
dllist.append('kitten');
dllist.append('fish');
dllist.append('birdy');
dllist.append('president-trump');
console.log(dllist);
console.log(dllist.forwardString());
console.log(dllist.backwardString());
dllist.insert(0, 'xxxx');
console.log(dllist);
console.log(dllist.backwardString());
dllist.insert(7,'item1');
dllist.insert(7,'item2');
dllist.insert(7,'item3');
dllist.insert(7,'item4');
dllist.insert(7,'item5');
dllist.insert(7,'item6');
dllist.insert(7,'item7');
console.log(dllist);
console.log(dllist.backwardString());
console.log(dllist.get(8));
console.log(dllist.indexOf('president-trump'));
console.log(dllist.indexOf('rabbit'));
console.log(dllist.indexOf('item1'));
console.log(dllist.indexOf('not-exist'));
console.log(dllist.update(6,'asshole'));
console.log(dllist);
console.log(dllist.backwardString());
// 11-->item3 change item3 to hehe
console.log(dllist.update(11,'hehe'));
console.log(dllist);
console.log(dllist.backwardString());
dllist.removeAt(0);
console.log(dllist);
console.log(dllist.backwardString());
dllist.removeAt(12);
console.log(dllist);
console.log(dllist.backwardString());
dllist.removeAt(11);
console.log(dllist);
console.log(dllist.backwardString());
dllist.removeAt(5);
console.log(dllist);
console.log(dllist.backwardString());
Output:
下面是我画的一些便于理解的示例图
insert()方法的示例图