用JS实现链表 --单链表
一、什么是链表
链表(linked list)是一种在物理上非连续、非顺序的数据结构,由若干个节点(node)所组成。
链表分为单向链表和双向链表:
单向链表的每一个节点包含两部分,一部分是存放数据的变量data,另一部分是指向下一个节点的指针next。
双向链表比单向链表复杂一些,它的每一个节点除了拥有data和next指针,还拥有指向前置节点的prev指针。
如果说数组在内存中的存储方式为顺序存储,那么链表在内存在的存储方式则是随机存储。
二、链表节点的实现
class Node {
constructor(value) {
this.value = value //节点的数据域
this.pre = null //前驱指针域
this.next = null //后继指针域
}
}
JS中并没有讨人厌的指针,节点的指针只是借用的C语言中的概念。之所以用prev和next两个指针域是为了实现双向链表,在实现单链表时,prev指针并没有用到。
三、单链表(Singky Linked List)的实现
(1).constructor构造函数内部实现:
class SinglyLinkedList {
constructor() {
this.size = 0 // 链表的长度
this.head = null //链表的头结点
}
}
(2).单链表应该具备的功能:
findN(n){
// 获取链表的第n个节点
}
append(element){
// 在链表尾部添加元素
}
find(item){
// 寻找值为item的节点
}
insert(item, element) {
// 在item元素后面插入值为element的新节点
}
remove(item){
// 在链表中删除值为item的节点
}
checkN(item){
// 查找值为item的节点是第几个
}
isEmpty(){
// 判断链表是否为空
}
getLength(){
// 获取链表的长度
}
clear(){
// 清空链表
}
1.获取链表的第n个节点:
findN(n){
// 获取链表的第n个节点
let currnode = this.head
while((n--) && currnode.next){
currnode = currnode.next
}
return currnode
}
2.在链表尾部添加元素:
append(element){
// 在链表尾部添加元素
let currnode = this.findN(this.size)
let newnode = new Node(element)
currnode.next = newnode
this.size ++
}
记得添加的元素要this.size++
3.寻找值为item的节点:
find(item){
// 寻找值为item的节点
let currnode = this.head
while(currnode && currnode.value != item){
currnode = currnode.next
}
return currnode
}
4.在item元素后面插入值为element的新节点:
insert(item, element) {
// 在item元素后面插入值为element的新节点
let currnode = this.find(item)
// 如果item不存在
if(!currnode){
return
}
let newnode = new Node(element)
newnode.next = currnode.next
currnode.next = newnode
this.size ++
}
记得添加的元素要this.size++
5.在链表中删除值为item的节点:
remove(item){
// 在链表中删除值为item的节点
let n = this.checkN(item)
let pre = this.findN(n - 1)
pre.next = pre.next.next
this.size --
}
记得删除了元素要this.size –
6.查找值为item的节点是第几个:
checkN(item){
// 查找值为item的节点是第几个
let currnode = this.find(item)
if(!currnode){
return -1
}
let res = this.head
let count = 0
while(res && res.value != currnode.value){
res = res.next
count ++
}
return count
}
如果查找的时候值为item的元素不存在,要另外判断,返回-1
7.判断链表是否为空 :
isEmpty(){
// 判断链表是否为空
return this.size == 0
}
长度为0就是空链表
8.获取链表的长度 :
getLength(){
// 获取链表的长度
return this.size
}
9.清空链表 :
clear(){
// 清空链表
this.head = null
this.size = 0
}
四、附上总代码:
class Node {
constructor(value) {
this.value = value //节点的数据域
this.pre = null //前驱指针域
this.next = null //后继指针域
}
}
class SinglyLinkedList {
constructor() {
this.size = 0 // 链表的长度
this.head = new Node('head') //链表的头结点
}
findN(n){
// 获取链表的第n个节点
let currnode = this.head
while((n--) && currnode.next){
currnode = currnode.next
}
return currnode
}
append(element){
// 在链表尾部添加元素
let currnode = this.findN(this.size)
let newnode = new Node(element)
currnode.next = newnode
this.size ++
}
find(item){
// 寻找值为item的节点
let currnode = this.head
while(currnode && currnode.value != item){
currnode = currnode.next
}
return currnode
}
insert(item, element) {
// 在item元素后面插入值为element的新节点
let currnode = this.find(item)
// 如果item不存在
if(!currnode){
return
}
let newnode = new Node(element)
newnode.next = currnode.next
currnode.next = newnode
this.size ++
}
remove(item){
// 在链表中删除值为item的节点
let n = this.checkN(item)
let pre = this.findN(n - 1)
pre.next = pre.next.next
this.size --
}
checkN(item){
// 查找值为item的节点是第几个
let currnode = this.find(item)
if(!currnode){
return -1
}
let res = this.head
let count = 0
while(res && res.value != currnode.value){
res = res.next
count ++
}
return count
}
isEmpty(){
// 判断链表是否为空
return this.size == 0
}
getLength(){
// 获取链表的长度
return this.size
}
clear(){
// 清空链表
this.head = null
this.size = 0
}
}
//以下测试用
const SL = new SinglyLinkedList()
SL.append(1)
SL.append(2)
SL.append(3)
SL.append(7)
SL.append(11)
SL.insert(7,9)
SL.remove(9)
console.dir(SL,{depth:10})
#五、 一些不确定与疑惑:
先列出来,以后有时间弄懂再写博客讲:
循环遍历的时候,链表的最后一个节点的next如果是null,好像不报错,但是最后一个节点的next的next如果是null,就会报错