• 无头双向链表的实现 —— Java【数据结构】


    目录

    1.无头双向链表

    2.基础代码

    3.双向链表中方法的实现

    3.1 头插法

    3.2 尾插法 

    3.3 删除第一次出现的关键字key  

    3.4 删除所有包含关键字key节点

    3.5 在给定的任意索引位置插入节点

    3.6 清空链表的所有节点

    3.7 打印链表

    3.8 求链表的长度

    3.9 查询链表是否给定的关键字key


    1.无头双向链表

     

    链表也是数组的一种形式,由各个节点组成,每个节点包括3部分val数据域、prev、next

    prev、next代表数据节点的两个指针,分别指向前后节点:

    prev存放上一个节点的地址

    next存放下一个节点的地址

    2.基础代码

    1. //ListNode 代表一个节点
    2. class Node {
    3. public Node val; //成员变量,结点里包含的属性
    4. public Node next;
    5. public Node prev;
    6. public Node() {
    7. this.val = val;
    8. }
    9. }
    10. //如下函数对双向列表进行增删查改 ---->定义在双向链表定义的类里
    11. public class MyLinkedList { //head属于链表的属性,只能定义在链表里
    12. //在MyLinkedList类里定义链表的方法
    13. }

    3.双向链表中方法的实现

    3.1 头插法

    1. //头插法 ---->定义一个插入节点node ListNode node
    2. public void addFirst(int data) {
    3. ListNode node = new ListNode(data); // new一个节点node, node 引用了对象,指代插入的节点
    4. //如果是第一次插入 判断是否为空链表
    5. if (this.head == null) {
    6. this.head = node;
    7. this.last = node;
    8. }else {
    9. node.next = this.head; //插入之后node在head之前,应符合链表结构 并且node作为新的头
    10. this.head.prev =node;
    11. this.head = node;
    12. }
    13. }

    3.2 尾插法 

    1. //尾插法
    2. public void addLast(int data) {
    3. ListNode node = new ListNode(data); // new一个节点node, node 引用了对象,指代插入的节点
    4. ListNode cur = this.head;
    5. if (cur == null) { //判断是否为空链表
    6. this.head = node;
    7. this.last = node;
    8. }else { //不为空执行遍历操作
    9. while(cur != null) {
    10. cur = cur.next;
    11. }
    12. this.last.next = node; //head last 代表头节点和尾结点
    13. node.prev =this.last;
    14. this.last = node;
    15. }
    16. }

    3.3 删除第一次出现的关键字key  

    1. //删除第一次出现关键字为key的节点
    2. public void remove(int key) {
    3. ListNode cur = this.head;
    4. while(cur != null) {
    5. if (cur.val == key) {
    6. if (cur == head) { //先判断关键字是否在头部
    7. head = head.next; //关键字在头部执行换头head
    8. if (head != null) {
    9. head.prev = null;
    10. }else {
    11. last = null;
    12. }
    13. } else { //不在头部考虑中间或者尾部,情况也不相同 //删除关键字在中间部位或者尾部
    14. cur.prev.next = cur.next; //前一个节点指向跳过当前节点指向当前的下一个 尾结点同样适用尾结点指向null
    15. if (cur.next != null) { //先考虑key关键字在中间
    16. cur.next.prev = cur.prev; //后往前指
    17. }else {
    18. last = last.prev; //考虑key关键字在尾部,,//后往前指
    19. }
    20. }
    21. return;
    22. }else {
    23. cur = cur.next;
    24. }
    25. }
    26. }

    3.4 删除所有包含关键字key节点

    1. //删除所有值为key的节点
    2. public void removeAllKey(int key) {
    3. ListNode cur = this.head;
    4. while(cur != null) {
    5. if (cur.val == key) {
    6. if (cur == head) { //先判断关键字是否在头部
    7. head = head.next; //关键字在头部执行换头head
    8. if (head != null) {
    9. head.prev = null;
    10. }else {
    11. last = null;
    12. }
    13. } else { //不在头部考虑中间或者尾部,情况也不相同 //删除关键字在中间部位或者尾部
    14. cur.prev.next = cur.next; //前一个节点指向跳过当前节点指向当前的下一个 尾结点同样适用尾结点指向null
    15. if (cur.next != null) { //先考虑key关键字在中间
    16. cur.next.prev = cur.prev; //后往前指
    17. }else {
    18. last = last.prev; //考虑key关键字在尾部,,//后往前指
    19. }
    20. }
    21. }else {
    22. cur = cur.next;
    23. }
    24. }
    25. }

    3.5 在给定的任意索引位置插入节点

             考虑插入不同位置的情况有差异,分开考虑开头、结尾、中间部分的插入

            解析:1.给定位置,要先知道下标的位置,提前先索引,找到插入位置处的节点

                       2.判断给出的位置是否合法(不能<0,不能超出链表的size())

                        3.如果插入在头部位置,和头插法一样,引用头插法方法即可

                        4.如果插入在尾部位置,和尾插法一样,引用尾插法方法即可
     

    1. //任意位置插入,第一个数据节点为0号下标
    2. //解析:分为头插、尾插和中间四个位置的改变
    3. public ListNode searchIndex(int index) { //先找到需要插入的索引位置(指定位置插入)
    4. ListNode cur = this.head;
    5. while (index != 0) {
    6. cur = cur.next;
    7. index--;
    8. }
    9. return cur; //cur为索引index位置处的节点
    10. }
    11. public void addIndex1(int index,int data) {
    12. ListNode node = new ListNode(data);
    13. if (index <0 || index > size()) { //插入索引位置需要判断合法不合法
    14. System.out.println("index不合法");
    15. return;
    16. }
    17. if (index == 0) { //,索引为0,在头部插入 也即是头插法
    18. addFirst(data); //引用定义好的头插法,传输插入数据data
    19. return;
    20. }
    21. if (index==size()) { //,索引位置=size()长度,在尾部插入 也即是尾插法
    22. addLast(data); //引用定义好的尾插法,传输插入数据data
    23. return;
    24. }
    25. ListNode cur = searchIndex(index); //找到索引位置处对应的节点cur
    26. cur.prev.next = node;
    27. // node.next = cur.prev.next; //当前cur的地址 //插在中间位置
    28. node.next = cur; //同上cur=cur.prev.next
    29. cur.prev = node;
    30. node.prev = cur.prev;
    31. }

    3.6 清空链表的所有节点

    解析:将所有节点置空即可,从头开始遍历,若cur不为null,将其prev和next置空

               最后要将last置空

    1. //解析:从头开始遍历,若cur不为null,将其prev和next置空
    2. public void clear() {
    3. ListNode cur = this.head;
    4. while(cur != null) {
    5. ListNode curNext = cur.next;
    6. cur.prev = null;
    7. cur.next = null;
    8. cur = curNext;
    9. }
    10. last =null;
    11. }

    3.7 打印链表

    1. // 打印顺序表
    2. public void display() { //和单链表打印一样
    3. ListNode cur = this.head;
    4. while(cur != null) {
    5. System.out.print(cur.val+" ");
    6. cur = cur.next;
    7. }
    8. System.out.println();
    9. }

    3.8 求链表的长度

    1. //得到单链表的长度
    2. public int size() {
    3. int count = 0; //方法里面的局部变量必须赋初值
    4. ListNode cur = this.head;
    5. while(cur != null) {
    6. count++;
    7. cur=cur.next;
    8. }
    9. return count;
    10. }

    3.9 查询链表是否给定的关键字key

    1. //查找是否包含关键字key是否在单链表当中
    2. public boolean contains(int key) {
    3. ListNode cur = this.head;
    4. while (cur != null) {
    5. if (cur.val == key) {
    6. return true;
    7. }
    8. cur = cur.next;
    9. }
    10. return false;
    11. }

  • 相关阅读:
    v-model的使用
    Linux Bridge(网桥)
    物流供应商实现供应链自动化的3种方法
    [云原生K8S] Yaml文件详解
    HTML脚本、字符实体、URL
    数字孪生技术的应用在能源行业案例解析
    【FPGA教程案例87】加解密1——基于FPGA的AES加解密算法verilog实现
    Python之第十一章 面向对象 --- 三大特征
    一款值得入手的双节电池1A电流线性充电芯片-YB4028
    DenseNet 浅析
  • 原文地址:https://blog.csdn.net/weixin_53939785/article/details/125633244