【DS】C6 -- 链表

250 阅读2分钟
1.数组的缺点

在很多编程语言中,数组的长度是固定的,在数组中,添加和删除元素也很麻烦。

JavaScript中数组的主要问题是,他们被实现成了对象,与其它语言的数组相比,效率很低。

如果发现数组在实际使用时很慢,就可以使用链表来代替。如果需要随机访问,数组仍然是更好的选择。

2.定义链表

链表是由一组节点组成的集合。每个节点都使用一个对象的引用指向它的后继。指向另一个结点的引用叫做链。

数组元素靠他们的位置进行引用,链表元素则是靠相互之间的关系进行引用。

遍历链表,就是跟着链接,从链表的首元素一直走到尾元素(但这不包含链表的头节点,头节点常常用来作为链表的接入点),链表的伪元素指向一个null节点。

  • 向链表中插入一个节点

    修改前驱,使其指向新加入的节点,而新加入的节点则指向原来前驱指向的节点。

  • 从链表中删除一个元素

    将待删除元素的前驱节点指向待删除元素的后继节点,同时,将待删除元素指向null,元素就删除成功了。

3.设计一个基于对象的链表
Node类 -- 表示节点
function Node(element){
	this.element = element;
	this.next = null;
}
LinkedList类 --对链表进行操作的方法
function LList(){
	//使用一个Node对象来保存该链表的头节点
	this.head = new Node("head");
	this.find = find;
	this.insert = insert;
	this.remove = remove;
	this.display = display;
}

head节点里的next属性被初始化为null,当有新元素插入时,next会指向新的元素。

插入新节点

查找

function find(item){
	var currNode = this.head;
	while (currNode.element != item){
		currNode = currNode.next;
	}
	return currNode;
}

在一个已知节点后面插入元素

function insert(newElement,item){
	var newNode = new Node(newElement);
	var currNode = this.find(item);
	newNode.next = current.next;
	current.next = newNode;
}

显示链表中的元素

function display(){
	var currNode = this.head;
	while(!(currNode.next == null)){
		//不显示头节点
		print(currNode.next.element);
		currNode = currNode.next;
	}
}
从链表中删除一个节点

寻找待删除节点前面的节点

function findPrevious(item){
	var currNode  = this.head;
	while(!(currNode.next == null)&&(currNode.next.element != item)){
		currNode = currNode.next;
	}
	return currNode;
}
function remove(item){
	var prevNode = this.findPrevious(item);
	if(!(preNode.next == null)){
		prevNode.next = prevNode.next.next;
	}
}
4.双向链表
function Node (elemnet){
	this.element = element;
	this.next = null;
	this.previous = null;
}

function insert(newElement,item){
	var newNode = new Node(newElement);
	var currNode = this.find(item);
	newNode.next = current.next;
	newNode.previous = current;
	current.next = newNode;
}

function remove(item){
	var currNode = this.find(item);
	if(!(currNode.next == null)){
		currNode.previous.next =currNode.next;
		currNode.next.previous = currNode.previous;
		currNode.next = null;
		currNode.previous = null;
	}
}

//查找最后的节点
function findLast(){
	var currNode = this.head;
	while(!(currNode.next == null)){
		currNode = currNode.next;
	}
	return currNode;
}

//反序显示双向链表中的元素
function dispReverse(){
	var currNode = this.head;
	currNode = this.findLast();
	while(!(currNode.previous == null)){
		print(currNode.element);
		currNode = currNode.previous;
	}
}
5.循环列表

循环链表和单项链表类似,节点类型都是一样的。唯一的区别是,在创建循环链表时,让其头节点的next属性指向它本身。

head.next = head;
function LList(){
	//使用一个Node对象来保存该链表的头节点
	this.head = new Node("head");
	this.head.next = this.head;
	this.find = find;
	this.insert = insert;
	this.remove = remove;
	this.display = display;
	this.findPrevious = findPrevious;
}
function display(){
	var currNode = this.head;
	while(!(currNode.next == null)&&!(currNode.next.element == "head")){
		//不显示头节点
		print(currNode.next.element);
		currNode = currNode.next;
	}
}