数据结构-双向链表的学习

认识双向链表,双向链表和单链表的区别

单链表
  1. 只能从头遍历到尾或者从尾遍历到头
  2. 链表的之间关联是单向的,原理是上一个链表中有一个指向下一个的指针
双链表
  1. 既可以从头遍历到尾,也可以从尾遍历到头
  2. 一个节点既有向前的引用,也有一个向后的引用
缺点
  1. 双向链表再插入和删除某个节点的节点的时候,需处理4个节点的引用,相对比单链表麻烦一些。

封装双向链表在这里插入图片描述

双向链表的结构如上图

1. 创建一个Node类

用来生成节点,表示节点信息。
对比单链表新增了一个前驱指针

//创建一个Node复制类,用来生成节点,表示节点信息
function Node(element) {
    this.element = element;
    this.next = null; //后继指针
    this.prev = null; //前驱指针
}
2. 封装一个双向链表
//封装双链表
function DoubleLink(element) {
    this.length = 0;
    this.head = null; //初始头结点
    this.tail = null; //新增尾结点

    //操作的方法(不全)
    this.append = append;
}
3. 向尾部追加元素

实现思想:

  1. 首先根据元素创建节点
  2. 判断链表是否是空链表:
    如果链表是空链表,将头部head替换为新节点node,新节点node的后继指针next指向尾部tail
    链表如果不是空链表,原链表中的尾部节点tail的后继指针next指向null,现在将它指向新的节点node;因为新节点的后继指针next和前驱指针pre都是null,所以将新节点node的前驱指针prev指向原尾部节点tail,原尾部节点tail替换成新节点node
  3. 最后将长度+1
//尾部追加项
function append(element) {
    let node = new Node(element);
    if (this.head == null) {
        this.head = node;
        node.next = tail;
    } else {
        this.fail.next = node;
        node.prev = this.tail;
        this.tail = node;
    }
    this.lenght++;
}
4. 实现转换字符串方法
1. 正向遍历
//1.正向遍历
function forwardString() {
    let current = this.head;
    let forwardString = "";

    while (current) {
        forwardString += "," + current.element;
        current = current.next;
    }
    return forwardString.slice(1);
}
2. 反向遍历
//2.反向遍历
function reserveString() {
    let current = this.tail;
    let reserveString = "";

    while (current) {
        reserveString += "," + current.element;
        current = current.pre;
    }
    return reserveString.slice(1);
}
3. 实现转换字符串方法
function toString() {
    return this.forwardString();
}
5. 向任意位置插入数据

实现方法:
一、首先判断position是否越界
二、元素插入链表第一个位置(position== 0)又分为两种情况:

  1. 链表为空,直接让head/tail指向新节点node
  2. 链表不为空,原来head的前驱指针prev指向新的节点node,新节点的后继指针next指向原来head,原head替换为新节点node

三、元素插入最后一个位置:将原tail的后继指针next指向新节点node,新节点node的前驱指针prev指向原tail节点,原tail替换为新节点node
四、元素插入中间位置,循环找到需要插入的位置,保存插入位置当前的节点和下一个节点信息,开始进行替换

  1. 新节点node的next/prev要指向前后的节点,也就是previous和current
  2. current的前驱指针prev要指向nodeprevious的后继指针next要指向node

五、最后将链表长度+1

function insert(position, element) {
    //1.判断越界问题
    if (position < 0 || position > this.lenght) return false;
    //2.创建新节点
    let node = new Node(element);
    //3.判断插入位置
    if (position === 0) {
        //判断链表是否为空
        if (this.head == null) {
            this.head = node;
            this.tail = node;
        } else {
            //链表不为空
            this.head.prev = node;
            node.next = this.head;
            this.head = node;
        }
    } else if (position === this.length) {
        //插入位置是最后
        this.tail.next = node;
        node.prev = this.tail;
        this.tail = node;
    } else {
        //在中间位子插入
        let index = 0;
        let current = this.head;
        let previous = null;

        //查找正确的位置
        while (index < position) {
            previous = current; //保存当前节点
            current = current.next; //保存下一个节点
            index++;
        }

        node.next = current;
        node.prev = previous;
        current.prev = node;
        previous.next = node;
    }
    this.length++;
    return true;
}
6. 移除元素

实现思想:
一、根据位置移除元素判断position是否越界
二、判断移出的位置:

  1. 移除位置是链表的第一个:
    1. 链表只有一个元素:直接将初始头节点head/尾节点tail设置为null
    2. 链表有多个元素:将原链表的第二个元素head.next替换为head,现在head的前驱指针prev指向null

二、移除的位置是最后一个:将尾部节点tail替换成原链表的倒数第二个,再将新尾节点的后继指针next指向null

三、移除的位置是中间元素:循环找到中间想要移除的值,保存要删除项的前一个节点和后一个节点,将前一个节点的后继指针指向后一个节点,后一个节点的前驱指针指向前一个节点

四、最后将长度length-1 五、返回删除的元素

function removeAt(position) {
    //1.判断position是否越界
    if (position === 0 || position >= this.length) return null;
    let  current = this.head;
    //2.判断移除的位置
    //移除的位置是链表第一个元素
    if (position === 0) {
        //链表只有一个元素
        if (this.length === 1) {
            this.head = null;
            this.tail = null;
        } else {
            current = this.tail;
            this.head = this.head.next;
            this.head.prev = null;
        }
    } else if (position === this.length) {
        this.tail = this.tail.prev;
        this.tail.next = null;
    }else{
        let index = 0;
        let previous = null;
        while(index < position){
            previous = current;
            current = current.next;
            index++;
        }
        previous.next = current.next;
        current.next.prev = previous;
    }
    this.length--
    return current.element
}
7. 获取指定元素位置

1.定义变量保存信息
2.通过循环查找和element相等的项
3.如果没有查找到,返回-1

function indexOf(element){
    let current = this.head;
    let index = 0;
    while(current){
        if(current.element == current){
            return index
        }
        index++;
        current = current.next
    }
    return -1;
}
8. 根据元素删除
function removeAt(element){
    let index = this.indexOf(element);
    return this.removeAt(index);
}

以上就是双链表的学习,如有错误,请留言,感谢~

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值