JavaScript 实现单向链表的操作

JavaScript实现链表 :使用ES6面向对象语法

链表: 数据的一种存储结构,一个链表包含若干个结点,每个结点至少包含一个数据域和一个指针域,指针域指向下一个结点

链表的分类:

  • 单向链表:每个结点都只有一个指向其下一个结点的指针域(next)
  • 双向链表:每个结点都有一个指向其前一个结点的指针域(prev)和一个指向其下一个结点的指针域(next)

头指针、头结点、首元结点的区别:

  • 头结点: 在单链表第一个元素结点之前设置的一个结点, 数据域可以不存任何信息,指针域指向单链表第一个元素的结点。头结点不是链表的必要元素
  • 头指针: 指向单链表的第一个结点的指针, 如果单链表有头结点,则头指针指向头结点 ,如果单链表没有头结点,则头指针指向第一个首元结点。头指针不能为空,头指针链表的必要元素
  • 首元结点: 单链表中第一个有数据元素的结点。如果单链表有头结点,则首元结点为头结点的下一个结点,如果单链表没有头结点,则首元结点就是单链表的第一个结点

在这里插入图片描述
在这里插入图片描述

头结点的优点:

  • 减少单链表添加删除时特殊情况的判断
  • 减少了程序的复杂性,主要是添加和删除在第一个有元素的结点(首元结点)上有区别,如果链表没有头结点,则删除或添加时都得需要判断一次首元结点,有了头结点以后,首元结点实际为链表的第二个结点,使得所有的元素结点的添加删除更具有统一性
  • 对于单链表来说, 头结点可有可无,但为了操作方便,一般情况下单链表都具有头结点

链表的设计:
一个是 Node 类用来表示结点,另一个是 SingleLinked 类提供插入结点、删除结点、遍历结点等一些操作

单链表代码:

//定义单向链表的结点类
class Node {
    constructor(data) {
        this.data = data   //数据域
        this.next = null   //指针域
    }
}

//定义单向链表类
class SingleLinked {
    constructor() {
        this.size = 0  //用来记录链表结点个数
        this.head = new Node('head')  //头指针:记录链表的起始地址  
        //与头结点区分:头结点是指带有数据结点中的第一个结点
        this.currNode = ''
    }
    
    //判断链表是否为空
    isEmpty() {
        return this.size === 0
    }
    
    //获取链表的长度
    getLength() {
        return this.size
    }
    
    //遍历单链表:不重复访问链表的每一个结点
    displayList() {
        let list = ''
        let currNode = this.head //指向链表的头指针
        while (currNode) {
            //若当前结点不为空
            list += currNode.data
            currNode = currNode.next //让指针指向当前结点的下一个结点
            if (currNode) {
                list += '->'
            }
        }
        console.log(list)
    }

    // 获取链表的最后一个结点
    findLast() {
        let currNode = this.head
        while (currNode.next) {
            currNode = currNode.next
        }
        return currNode
    }

    //尾插法 在单链表尾部插入元素
    appendNode(element) {
        var currNode = this.findLast() //找到链表最后一个结点
        var newNode = new Node(element) //创建一个新结点
        currNode.next = newNode
        newNode.next = null
        this.size++ //链表长度+1
    }

    //查找结点
    findNode(element) {
        let currNode = this.head
        while (currNode && (currNode.data !== element)) {
            currNode = currNode.next
        }
        return currNode
    }

    //指定元素位置后插入结点
    insertNode(item, element) {
        let itemNode = this.findNode(item);
        if (!itemNode) { //如果item元素不存在
            return;
        }
        let newNode = new Node(element);
        newNode.next = itemNode.next; //若currNode为最后一个节点,则currNode.next为空
        itemNode.next = newNode;
        this.size++;
    }

    //删除链表的某一个结点
    deleteNode(element) {
        if (!this.findNode(element)) {
            console.log("要删除结点不存在!")
            return
        }
        if ('head' === element) {
            console.log("整个链表将被删除")
            this.head = null
            this.size = 0
            return
        }
        //思想:让currNode结点的next指向下一个结点
        let currNode = this.head
        while (currNode.next.data !== element) {
            currNode = currNode.next
        }
        currNode.next = currNode.next.next

        //与上述删除思想相同
        // let currNode = this.head
        // while (currNode.next) {
        //     if (currNode.next.data === element) {
        //         currNode.next = currNode.next.next
        //         break
        //     }
        //     currNode = currNode.next
        // }

        //思想:加入一个前驱结点 preNode
        // let currNode = this.head
        // let preNode = null
        // while (currNode.data !== element) {
        //     currNode = currNode.next
        //     preNode = currNode
        // }
        // preNode.next = currNode.next

        this.size--
    }
}

检测代码:

//创建一个空链表
let slist=new SingleLinked()
//判断链表是否为空
console.log(slist.isEmpty())
//尾插法插入元素
slist.appendNode(0)
//遍历单链表
slist.displayList()
//使用尾插法依次插入数组序列
let arr=[2,4,6,8,10]
for(var i=0;i<arr.length;i++){
    slist.appendNode(arr[i])
}
slist.displayList()
//在指定位置插入元素
slist.insertNode(8,9)
slist.displayList()
//输出链表的长度(不包括头结点head)
console.log(slist.getLength())
//删除结点元素
slist.deleteNode(4)
//遍历
slist.displayList()

在这里插入图片描述

参考之后所写文章: JavaScript 实现双向链表的操作

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值