Java链表原理与实例讲解 :修改快但是查询慢

  1. 链表是以节点的方式来存储,是链式存储
  2. 每个节点包含 data 域, next 域:指向下一个节点.
  3. 链表的各个节点不一定是连续存储.
  4. 链表分带头节点的链表和没有头节点的链表,根据实际的需求来确定

单链表的创建示意图(添加) 显示单向链表的分析

  1. head节点: 不存放具体的数据, 作用就是表示单链表头next
  2. HeroNode 数据next
  3. HeroNode数据next
  4. 添加: 先创建一个head头节点, 作用就是表示单链表的头,后面我们每添加一个节点, 就直接加入到链表的最后
  5. 遍历: 通过一个辅助遍历, 帮助遍历整个链表

应用实例

  • 使用带head头的单向链表实现 –水浒英雄排行榜管理
    1. 完成对英雄人物的增删改查操作, 注: 删除和修改,查找可以考虑学员独立完成,也可带学员完成
    2. 第一种方法在添加英雄时,直接添加到链表的尾部
      package DataStructures;
      
      public class SingleLinkedList {
          public static void main(String[] args) {
              // 进行测试
              // 先创建节点
              HeroNode hero1 =  new HeroNode (1,"宋宋", "江江");
              HeroNode hero2 =  new HeroNode (2,"文文", "雨雨");
              HeroNode hero3 =  new HeroNode (3,"哈哈", "嘿嘿");
              HeroNode hero4 =  new HeroNode (4,"依依", "落落");
              // 创建要给链表
              SingleLinkedListD singleLinkedListD = new SingleLinkedListD();
              // 加入
              singleLinkedListD.add(hero1);
              singleLinkedListD.add(hero2);
              singleLinkedListD.add(hero3);
              singleLinkedListD.add(hero4);
              // 显示
              singleLinkedListD.list();
          }
      }
      
      // 定义SingleLinked 管理我们的英雄
      class SingleLinkedListD {
          //先初始化一个头节点, 头节点不要动,
          private HeroNode head = new HeroNode(0,"","");
          public void add(HeroNode heroNode) {
              //因为head节点不能动, 因此我们需要一个辅助变量temp
              HeroNode temp = head;
              // 遍历链表, 找到最后
              while(true) {
                  // 找到链表的最后
                  if (temp.next == null) {
                      break;
                  }
      //            如果没有找到最后,就将temp后移
                  temp = temp.next;
              }
              // 当退出while循环时, temp就指向了链表的最后
              // 将最后这个节点的next 指向 新的节点
              temp.next = heroNode;
          }
          //显示链表(遍历)
          public void list() {
              // 判断链表是否为空
              if (head.next == null) {
                  System.out.println("链表为空");
                  return;
              }
              // 因为头节点, 不能动 因此我们需要一个辅助变量来遍历
              HeroNode temp = head.next;
              while(true) {
                  // 判断是否到链表最后
                  if (temp == null) {
                      break;
                  }
                  // 输出节点信息
                  System.out.println(temp);
                  // 将temp后移, 一定小心
                  temp = temp.next;
              }
          }
      }
      // 定义HeroNode , 每个HeroNode 对象就是一个节点
      class HeroNode {
          public int no;
          public String name;
          public String nickname;
          public HeroNode next; // 指向下一个节点
      
          // 构造器
          public HeroNode(int no, String hName, String hNickname) {
              this.no = no;
              this.name = hName;
              this.nickname = hNickname;
          }
          // 为了显示方法, 我们重新toString
          @Override
          public String toString() {
              return "HeroNode{" +
                      "no=" + no +
                      ", name='" + name + '\'' +
                      ", nickname='" + nickname;
          }
      }
      
    3. 第二种方式在添加英雄时,根据排名将英雄插入到指定位置(如果有这个排名,则添加失败,并给出提示)
      package DataStructures;
      
      public class SingleLinkedList {
          public static void main(String[] args) {
              // 进行测试
              // 先创建节点
              HeroNode hero1 =  new HeroNode (1,"宋宋", "江江");
              HeroNode hero2 =  new HeroNode (2,"文文", "雨雨");
              HeroNode hero3 =  new HeroNode (3,"哈哈", "嘿嘿");
              HeroNode hero4 =  new HeroNode (4,"依依", "落落");
              // 创建要给链表
              SingleLinkedListD singleLinkedListD = new SingleLinkedListD();
              // 加入
      //        singleLinkedListD.add(hero1);
      //        singleLinkedListD.add(hero2);
      //        singleLinkedListD.add(hero3);
      //        singleLinkedListD.add(hero4);
      
              // 加入按照编号的顺序
              singleLinkedListD.addByOrder(hero1);
              singleLinkedListD.addByOrder(hero2);
              singleLinkedListD.addByOrder(hero3);
              singleLinkedListD.addByOrder(hero4);
              singleLinkedListD.addByOrder(hero3);
              // 显示
              singleLinkedListD.list();
          }
      }
      
      // 定义SingleLinked 管理我们的英雄
      class SingleLinkedListD {
          //先初始化一个头节点, 头节点不要动,
          private HeroNode head = new HeroNode(0,"","");
      
          public void add(HeroNode heroNode) {
              //因为head节点不能动, 因此我们需要一个辅助变量temp
              HeroNode temp = head;
              // 遍历链表, 找到最后
              while(true) {
                  // 找到链表的最后
                  if (temp.next == null) {
                      break;
                  }
      //            如果没有找到最后,就将temp后移
                  temp = temp.next;
              }
              // 当退出while循环时, temp就指向了链表的最后
              // 将最后这个节点的next 指向 新的节点
              temp.next = heroNode;
          }
      
      //    第二种方式在添加英雄时,根据排名将英雄插入到指定位置(如果有这个排名,则添加失败,并给出提示)
            public void addByOrder (HeroNode heroNode) {
              // 因为头节点不能动, 因此我们仍然通过一个辅助指针(变量) 来帮助找到添加的位置
                //因为单链表, 因此我们找的temp 是位于添加位置的前一个节点, 否则插入不了
                HeroNode temp = head;
                boolean flag = false; // flag标志添加的编号是否存在, 默认为false
                while(true) {
                    if (temp.next == null) { // 说明temp已经在链表的最后
                        break;//
      
                    }
                    if (temp.next.no > heroNode.no) { // 位置找到, 就在temp 的后面插入
                        break;
      
                    } else if (temp.next.no == heroNode.no) {
                        // 说明希望添加的heroNode的编号已然存在
                        flag = true; // 说明编号存在
                        break;
                    }
                    temp = temp.next; // 后移, 遍历当前链表
      
                }
                // 判断flag 的值
                if (flag) { // 不能添加,说明编号存在
                    System.out.println("准备插入的英雄编号%d已经存在了, 不能加入\n" + heroNode.no);
                } else {
                    // 插入到链表中 temp的后面
                    heroNode.next = temp.next;
                    temp.next = heroNode;
                }
            }
      
      
          //显示链表(遍历)
          public void list() {
              // 判断链表是否为空
              if (head.next == null) {
                  System.out.println("链表为空");
                  return;
              }
              // 因为头节点, 不能动 因此我们需要一个辅助变量来遍历
              HeroNode temp = head.next;
              while(true) {
                  // 判断是否到链表最后
                  if (temp == null) {
                      break;
                  }
                  // 输出节点信息
                  System.out.println(temp);
                  // 将temp后移, 一定小心
                  temp = temp.next;
              }
          }
      }
      // 定义HeroNode , 每个HeroNode 对象就是一个节点
      class HeroNode {
          public int no;
          public String name;
          public String nickname;
          public HeroNode next; // 指向下一个节点
      
          // 构造器
          public HeroNode(int no, String hName, String hNickname) {
              this.no = no;
              this.name = hName;
              this.nickname = hNickname;
          }
          // 为了显示方法, 我们重新toString
          @Override
          public String toString() {
              return "HeroNode{" +
                      "no=" + no +
                      ", name='" + name + '\'' +
                      ", nickname='" + nickname;
          }
      }
      

修改链表

package DataStructures;

public class SingleLinkedList {
    public static void main(String[] args) {
        // 进行测试
        // 先创建节点
        HeroNode hero1 =  new HeroNode (1,"宋宋", "江江");
        HeroNode hero2 =  new HeroNode (2,"文文", "雨雨");
        HeroNode hero3 =  new HeroNode (3,"哈哈", "嘿嘿");
        HeroNode hero4 =  new HeroNode (4,"依依", "落落");
        // 创建要给链表
        SingleLinkedListD singleLinkedListD = new SingleLinkedListD();
        // 加入
//        singleLinkedListD.add(hero1);
//        singleLinkedListD.add(hero2);
//        singleLinkedListD.add(hero3);
//        singleLinkedListD.add(hero4);

        // 加入按照编号的顺序
        singleLinkedListD.addByOrder(hero1);
        singleLinkedListD.addByOrder(hero2);
        singleLinkedListD.addByOrder(hero3);
        singleLinkedListD.addByOrder(hero4);
        singleLinkedListD.addByOrder(hero3);
        //显示
        singleLinkedListD.list();
        
        HeroNode newHeroNode = new HeroNode(2,"文","雨~~");
        singleLinkedListD.update(newHeroNode);

        System.out.println("修改后的链表情况");
        singleLinkedListD.list();


    }
}

// 定义SingleLinked 管理我们的英雄
class SingleLinkedListD {
    //先初始化一个头节点, 头节点不要动,
    private HeroNode head = new HeroNode(0,"","");

    public void add(HeroNode heroNode) {
        //因为head节点不能动, 因此我们需要一个辅助变量temp
        HeroNode temp = head;
        // 遍历链表, 找到最后
        while(true) {
            // 找到链表的最后
            if (temp.next == null) {
                break;
            }
//            如果没有找到最后,就将temp后移
            temp = temp.next;
        }
        // 当退出while循环时, temp就指向了链表的最后
        // 将最后这个节点的next 指向 新的节点
        temp.next = heroNode;
    }

//    第二种方式在添加英雄时,根据排名将英雄插入到指定位置(如果有这个排名,则添加失败,并给出提示)
      public void addByOrder (HeroNode heroNode) {
        // 因为头节点不能动, 因此我们仍然通过一个辅助指针(变量) 来帮助找到添加的位置
          //因为单链表, 因此我们找的temp 是位于添加位置的前一个节点, 否则插入不了
          HeroNode temp = head;
          boolean flag = false; // flag标志添加的编号是否存在, 默认为false
          while(true) {
              if (temp.next == null) { // 说明temp已经在链表的最后
                  break;//

              }
              if (temp.next.no > heroNode.no) { // 位置找到, 就在temp 的后面插入
                  break;

              } else if (temp.next.no == heroNode.no) {
                  // 说明希望添加的heroNode的编号已然存在
                  flag = true; // 说明编号存在
                  break;
              }
              temp = temp.next; // 后移, 遍历当前链表

          }
          // 判断flag 的值
          if (flag) { // 不能添加,说明编号存在
              System.out.println("准备插入的英雄编号%d已经存在了, 不能加入\n" + heroNode.no);
          } else {
              // 插入到链表中 temp的后面
              heroNode.next = temp.next;
              temp.next = heroNode;
          }
      }
// 修改节点的信息, 根据no的编号来修改, 即no编号不能改
    //说明
    // 1. 根据newHeroNode 的no来修改即可
    public void update(HeroNode newHeroNode) {
        // 判断是否空
        if (head.next == null) {
            System.out.println("链表为空");
            return;
        }
        // 根据需要修改的节点, 根据no编写
        // 定义一个辅助变量
        HeroNode temp = head.next;
        boolean flag = false; // 表示是否找到该节点
        while(true) {
            if (temp == null) {
                break;// 已经遍历完链表
            }
            if (temp.no == newHeroNode.no) {
                //找到
                flag = true;
                break;
            }
            temp = temp.next;
        }
        //根据flag 判断是否找到要修改的节点
        if (flag) {
            temp.name = newHeroNode.name;
            temp.nickname = newHeroNode.nickname;
        } else { // 没有找到
            System.out.println("没有找到编号为%d 的节点, 不能修改\n" + newHeroNode.no);
        }
    }

    //显示链表(遍历)
    public void list() {
        // 判断链表是否为空
        if (head.next == null) {
            System.out.println("链表为空");
            return;
        }
        
        // 因为头节点, 不能动 因此我们需要一个辅助变量来遍历
        HeroNode temp = head.next;
        while(true) {
            // 判断是否到链表最后
            if (temp == null) {
                break;
            }
            // 输出节点信息
            System.out.println(temp);
            // 将temp后移, 一定小心
            temp = temp.next;
        }
    }
}
// 定义HeroNode , 每个HeroNode 对象就是一个节点
class HeroNode {
    public int no;
    public String name;
    public String nickname;
    public HeroNode next; // 指向下一个节点

    // 构造器
    public HeroNode(int no, String hName, String hNickname) {
        this.no = no;
        this.name = hName;
        this.nickname = hNickname;
    }
    // 为了显示方法, 我们重新toString
    @Override
    public String toString() {
        return "HeroNode{" +
                "no=" + no +
                ", name='" + name + '\'' +
                ", nickname='" + nickname;
    }
}

删除链表

从单链表中删除一个节点的思路

  1. 我们先找到需要删除的这个节点的前一个节点temp
  2. temp.next = temp.next.next;
  3. 被删除的节点,将不会有其他引用指向, 会被垃圾回收机制回收
    package DataStructures;
    
    public class SingleLinkedList {
        public static void main(String[] args) {
            // 进行测试
            // 先创建节点
            HeroNode hero1 =  new HeroNode (1,"宋宋", "江江");
            HeroNode hero2 =  new HeroNode (2,"文文", "雨雨");
            HeroNode hero3 =  new HeroNode (3,"哈哈", "嘿嘿");
            HeroNode hero4 =  new HeroNode (4,"依依", "落落");
            // 创建要给链表
            SingleLinkedListD singleLinkedListD = new SingleLinkedListD();
            // 加入
    //        singleLinkedListD.add(hero1);
    //        singleLinkedListD.add(hero2);
    //        singleLinkedListD.add(hero3);
    //        singleLinkedListD.add(hero4);
    
            // 加入按照编号的顺序
            singleLinkedListD.addByOrder(hero1);
            singleLinkedListD.addByOrder(hero2);
            singleLinkedListD.addByOrder(hero3);
            singleLinkedListD.addByOrder(hero4);
            singleLinkedListD.addByOrder(hero3);
            //显示
            singleLinkedListD.list();
    
            HeroNode newHeroNode = new HeroNode(2,"文","雨~~");
            singleLinkedListD.update(newHeroNode);
            System.out.println("修改后的链表情况");
            singleLinkedListD.list();
            
            // 删除一个节点
            singleLinkedListD.del(1);
            System.out.println("删除后的链表情况");
            singleLinkedListD.list();
    
        }
    }
    
    // 定义SingleLinked 管理我们的英雄
    class SingleLinkedListD {
        //先初始化一个头节点, 头节点不要动,
        private HeroNode head = new HeroNode(0,"","");
    
        public void add(HeroNode heroNode) {
            //因为head节点不能动, 因此我们需要一个辅助变量temp
            HeroNode temp = head;
            // 遍历链表, 找到最后
            while(true) {
                // 找到链表的最后
                if (temp.next == null) {
                    break;
                }
    //            如果没有找到最后,就将temp后移
                temp = temp.next;
            }
            // 当退出while循环时, temp就指向了链表的最后
            // 将最后这个节点的next 指向 新的节点
            temp.next = heroNode;
        }
    
    //    第二种方式在添加英雄时,根据排名将英雄插入到指定位置(如果有这个排名,则添加失败,并给出提示)
          public void addByOrder (HeroNode heroNode) {
            // 因为头节点不能动, 因此我们仍然通过一个辅助指针(变量) 来帮助找到添加的位置
              //因为单链表, 因此我们找的temp 是位于添加位置的前一个节点, 否则插入不了
              HeroNode temp = head;
              boolean flag = false; // flag标志添加的编号是否存在, 默认为false
              while(true) {
                  if (temp.next == null) { // 说明temp已经在链表的最后
                      break;//
    
                  }
                  if (temp.next.no > heroNode.no) { // 位置找到, 就在temp 的后面插入
                      break;
    
                  } else if (temp.next.no == heroNode.no) {
                      // 说明希望添加的heroNode的编号已然存在
                      flag = true; // 说明编号存在
                      break;
                  }
                  temp = temp.next; // 后移, 遍历当前链表
    
              }
              // 判断flag 的值
              if (flag) { // 不能添加,说明编号存在
                  System.out.println("准备插入的英雄编号%d已经存在了, 不能加入\n" + heroNode.no);
              } else {
                  // 插入到链表中 temp的后面
                  heroNode.next = temp.next;
                  temp.next = heroNode;
              }
          }
    // 修改节点的信息, 根据no的编号来修改, 即no编号不能改
        //说明
        // 1. 根据newHeroNode 的no来修改即可
        public void update(HeroNode newHeroNode) {
            // 判断是否空
            if (head.next == null) {
                System.out.println("链表为空");
                return;
            }
            // 根据需要修改的节点, 根据no编写
            // 定义一个辅助变量
            HeroNode temp = head.next;
            boolean flag = false; // 表示是否找到该节点
            while(true) {
                if (temp == null) {
                    break;// 已经遍历完链表
                }
                if (temp.no == newHeroNode.no) {
                    //找到
                    flag = true;
                    break;
                }
                temp = temp.next;
            }
            //根据flag 判断是否找到要修改的节点
            if (flag) {
                temp.name = newHeroNode.name;
                temp.nickname = newHeroNode.nickname;
            } else { // 没有找到
                System.out.println("没有找到编号为%d 的节点, 不能修改\n" + newHeroNode.no);
            }
        }
    
        //删除节点
        //思路
        //1.head不能动 因此我们需要temp辅助节点找到待删除节点的前一个节点
        // 2. 说明我们在比较时,时temp.next.no和需要删除的节点的no比较
        public void del(int no) {
            HeroNode temp = head;
            boolean flag = false; // 标志是否找到待删除节点的
            while (true) {
                if (temp.next == null) { //已经到链表的最后
                    break;
                }
                if (temp.next.no == no) {
                    // 找到了待删除的前一个节点temp
                    flag = true;
                    break;
                }
                temp = temp.next;// temp后移 遍历
            }
            //判断flag
            if (flag) { // 找到
                // 可以删除
                temp.next = temp.next.next;
            }else {
                System.out.println("要删除的%d 节点不存在\n" + no);
            }
        }
        //显示链表(遍历)
        public void list() {
            // 判断链表是否为空
            if (head.next == null) {
                System.out.println("链表为空");
                return;
            }
            // 因为头节点, 不能动 因此我们需要一个辅助变量来遍历
            HeroNode temp = head.next;
            while(true) {
                // 判断是否到链表最后
                if (temp == null) {
                    break;
                }
                // 输出节点信息
                System.out.println(temp);
                // 将temp后移, 一定小心
                temp = temp.next;
            }
        }
    }
    // 定义HeroNode , 每个HeroNode 对象就是一个节点
    class HeroNode {
        public int no;
        public String name;
        public String nickname;
        public HeroNode next; // 指向下一个节点
    
        // 构造器
        public HeroNode(int no, String hName, String hNickname) {
            this.no = no;
            this.name = hName;
            this.nickname = hNickname;
        }
        // 为了显示方法, 我们重新toString
        @Override
        public String toString() {
            return "HeroNode{" +
                    "no=" + no +
                    ", name='" + name + '\'' +
                    ", nickname='" + nickname;
        }
    }
    
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值