【Java數據結構與算法】單鏈表

單鏈表

鏈表介紹

鏈表是有序的列表,但是它的內存中的存儲如下
在這裏插入圖片描述
結論:

  1. 鏈表是以節點的方式來存儲的,是鏈式存儲
  2. 每個節點包括date域:保存數據 和next域:指向下一個節點
  3. 如圖:發現鏈表的各個節點不一定是連續存放的
  4. 鏈表分帶頭節點的鏈表,和沒有頭節點的鏈表,根據實際需求來確定

單鏈表(帶頭節點)邏輯結構示意圖如下:
在這裏插入圖片描述
帶頭節點單鏈表思路
添加創建:

  1. 先創建一個head頭節點,作用就是表示單鏈表的頭
  2. 後面我們每添加一個節點,就直接加入到鏈表的最後

遍歷:

  1. 通過一個輔助遍歷,幫助遍歷整個鏈表

按照編號的順序添加思路

  1. 首先找到新添加的節點的位置,是通過輔助變量(指針),通過遍歷來搞定的
  2. 新的節點.next = temp.next
  3. 將temp.next = 新的節點 按照順序添加

刪除節點思路

  1. 我們先找到需要刪除這個節點的前一個節點temp
  2. temp.next=temp.next.next;
  3. 被刪除的節點,將不會有其他引用指向,會被垃圾回收機制回收

代碼實現

import sun.nio.cs.ext.MacHebrew;

import javax.management.MBeanRegistrationException;
import javax.swing.plaf.nimbus.AbstractRegionPainter;

public class SingLinkedListDemo{
    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, "林沖", "豹子頭");
        //創建一個列表
        SingleLinkedList singleLinkedList = new SingleLinkedList();
        //加入
        /*singleLinkedList.add(hero1);
        singleLinkedList.add(hero2);
        singleLinkedList.add(hero3);
        singleLinkedList.add(hero4);*/
        //加入,按照編號的順序
        singleLinkedList.addByOrder(hero1);
        singleLinkedList.addByOrder(hero4);
        singleLinkedList.addByOrder(hero3);
        singleLinkedList.addByOrder(hero2);
        //測試修改節點的代碼
        HeroNode newHero2 = new HeroNode(2, "小盧", "玉麒麟~~");
        singleLinkedList.update(newHero2);
        //刪除一個節點
        singleLinkedList.del(2);
        //顯示
        singleLinkedList.list();
    }
}
//定義SingleLinkedList
class SingleLinkedList{
    //先初始化一個頭節點,頭節點不要動,固定的位置,不存放具體的數據
    private HeroNode head = new HeroNode(0,"","");
    //添加節點到單向鏈表
    //思路。不考慮編號的順序時
    //1.找到當前鏈表的最後節點
    //2.將最後整個節點的next 指向 新的節點
    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是位於添加位置的前1個節點
        HeroNode temp = head;
        boolean flag = false;//標誌添加的編號是否存在,默認爲false
        while (true){
            if (temp.next == null){//說明temp在鏈表最後
                break;//
            }
            if (temp.next.no > heroNode.no){//位置找到了,就在temp的後面輸入
                break;
            }else if (temp.next.no == heroNode.no){//說明添加數據的編號已經存在了
                flag = true;//說明編號存在、
                break;
            }
            temp = temp.next;//後移,相當於遍歷
        }
        //判斷flag的值
        if (flag){//如果爲真,就不能添加,說明編號存在
            System.out.printf("準備插入英雄編號%d已經存在,不能加入\n",heroNode.no);
        }else{
            //插入到鏈表當中,temp的後面
            heroNode.next = temp.next;
            temp.next = heroNode;
        }
    }
    //修改節點的信息,根據no編號來修改,所以編號不能修改
    public void update(HeroNode heroNode){
        //判斷是否爲空
        if (head.next == null){
            System.out.println("鏈表爲空!");
            return;
        }
        //找到需要修改的節點,根據no編號查找
        //定義一個temp輔助變量
        HeroNode temp = head.next;
        boolean flag = false;//表示是否找到該節點
        while (true){
            if (temp == null){
                break;//到鏈表最後了,沒有數據了,已經遍歷結束了
            }
            if (temp.no == heroNode.no){
                //找到了節點
                flag = true;
                break;
            }
            temp = temp.next;
        }
        //根據flag判斷是否找到要修改的節點
        if (flag){
            temp.name = heroNode.name;
            temp.nickName = heroNode.nickName;
        }else {//沒有找到節點
            System.out.printf("沒有找到編號%d的節點,不能修改\n",heroNode.no);
        }
    }
    //刪除節點
    //1.head不能動,因此還是需要temp輔助節點,找打需要刪除節點的前一個節點
    //2.說明我們在比較時,是temp.next.no和需要刪除的節點進行比較
    public void del(int no){
        HeroNode temp = head;
        boolean flag = false;//標記是否找到需要刪除的節點
        while (true){
            if (temp.next == null){//說明遍歷結束,已經到最後了
                break;
            }
            if (temp.next.no == no){
                //說明找到了需要刪除的節點的前一節點
                flag = true;
                break;
            }
            temp = temp.next;//temp後移進行遍歷
        }
        //判斷flag
        if (flag){
            //找到,可以刪除
            temp.next = temp.next.next;//相當於把需要刪除的節點排除出去了
        }else{
            System.out.printf("要刪除的%d節點不存在",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 name,String nickName){
        this.no = no;
        this.name = name;
        this.nickName = nickName;
    }
    //爲了顯示方法,我們重新toString
    @Override
    public String toString() {
        return "[HeroNode{" +
                "no=" + no +
                ", name='" + name + '\'' +
                ", nickName='" + nickName + "]";
    }
}

編程我也是初學者,難免有理解錯誤的地方,希望大家看完之後,發現錯誤可以評論出來,謝謝大家

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章