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

雙向鏈表

單向鏈表的缺點分析

  1. 單向鏈表,查找的方向只能是一個方向,而雙向鏈表可以向前或者向後查找
  2. 單向鏈表不能自我刪除,需要靠輔助節點,而雙向鏈表,則可以自我刪除,所以前面刪除單向鏈表節點時,需要找到temp的下一個節點來刪除
  3. 如若未了解單鏈表請參考–>單鏈表點這裏

雙向鏈表示意圖如下:
雙向鏈表

分析雙向鏈表的遍歷,添加,修改,刪除的操作思路

遍歷方式和單向鏈表一樣,只是可以向前,也可以向後查找
添加(默認添加到雙向鏈表的最後)

  1. 先找到雙線鏈表的最後節點
  2. temp.next指向新的節點,temp.next=newHeroNode
  3. newHerNOde.pre=temp;

修改思路和單向鏈表一樣
刪除

  1. 因爲是雙線鏈表,因此,我們可以實現自我刪除某個節點
  2. 之間找到要刪除的這個節點,比如temp
  3. temp.per.next=temp.next,(把temp前一個節點的next指向了,temp後一個的節點)
  4. temp.next.pre=temp.pre

代碼實現

package DataType;

public class DoubleLinkedLIstDemo {
    public static void main(String[] args){
        //測試
        System.out.println("雙向鏈表的測試~~~");
        //先創建節點
        HeroNode2 hero1 = new HeroNode2(1, "松江", "及時雨");
        HeroNode2 hero2 = new HeroNode2(2, "盧俊義", "玉麒麟");
        HeroNode2 hero3 = new HeroNode2(3, "吳用", "智多星");
        HeroNode2 hero4 = new HeroNode2(4, "林沖", "豹子頭");
        //創建一個雙向鏈表
        DoubleLinkedList doubleLinkedList = new DoubleLinkedList();
        doubleLinkedList.add(hero1);
        doubleLinkedList.add(hero2);
        doubleLinkedList.add(hero3);
        doubleLinkedList.add(hero4);
        doubleLinkedList.list();
        //修改測試
        HeroNode2 newHeroNode = new HeroNode2(4, "董小宇", "董小宇");
        doubleLinkedList.update(newHeroNode);
        System.out.println("修改後的鏈表是~~~");
        doubleLinkedList.list();
        //刪除測試
        doubleLinkedList.del(3);
        System.out.println("刪除後的鏈表情況~~~");
        doubleLinkedList.list();
        //測試按照順序添加
        HeroNode2 addHeroNode = new HeroNode2(3, "董大宇", "董大宇");
        doubleLinkedList.addByOrder(addHeroNode);
        System.out.println("按照順序後的鏈表情況~~~");
        doubleLinkedList.list();
    }
}
//創建一個雙向鏈表的類
class DoubleLinkedList{
    ///先初始化一個頭節點,頭節點不要動,固定的位置,不存放具體的數據
    private HeroNode2 head = new HeroNode2(0,"","");
    //返回頭節點
    public HeroNode2 getHead(){
        return head;
    }
    //遍歷雙向鏈表的方法
    public void list(){
        //先判斷鏈表是否爲空
        if(head.next == null){
            System.out.println("鏈表爲空!!");
            return;
        }
        //因爲頭節點,不能動,因此還需要輔助變量來遍歷
        HeroNode2 temp = head.next;
        while (true){
            //判斷是否到了鏈表最後
            if (temp == null){
                break;
            }
            //輸出節點的信息
            System.out.println(temp);
            //將temp後移
            temp = temp.next;
        }
    }
    //添加一個節點,到雙向鏈表的最後
    public void add(HeroNode2 heroNode){
        //因爲head不能動,因此我們需要一個輔助變量 temp
        HeroNode2 temp = head;
        //遍歷鏈表,找到最後
        while (true){
            //找到鏈表的最後
            if (temp.next == null){
                break;
            }
            //如果沒有找到最後,就將temp後移
            temp = temp.next;
        }
        //當推出while循環時,temp就指向了鏈表的最後
        //構成一個雙向鏈表
        temp.next = heroNode;
        heroNode.pre = temp;
    }
    //添加數據,按照順序來
    public void addByOrder(HeroNode2 heroNode){
        //還是因爲頭節點不能動,我們仍然通過輔助指針來幫助
        //因爲雙向鏈表,因此我們找的temp
        HeroNode2 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;
            heroNode.pre = temp.next.pre;
            temp.next.pre = heroNode;
        }
    }
    //修改一個節點的內容,可以看到雙向鏈表節點修改和單向鏈表一樣,只是類型不一樣,
    public void update(HeroNode2 heroNode){
        //判斷是否爲空
        if (head.next == null){
            System.out.println("鏈表爲空!");
            return;
        }
        //找到需要修改的節點,根據no編號查找
        //定義一個temp輔助變量
        HeroNode2 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.對於雙向鏈表,可以直接找到要刪除的節點
    //2.找到後自我刪除即可
    public void del(int no){
        //判斷當前當前列表是否爲空
        if (head.next == null){//空鏈表
            System.out.println("鏈表空,無法刪除!");
            return;
        }
        HeroNode2 temp = head.next;//輔助指針
        boolean flag = false;//標記是否找到需要刪除的節點
        while (true){
            if (temp == null){//說明遍歷結束,已經到最後了
                break;
            }
            if (temp.no == no){
                //說明找到了需要刪除的節點temp
                flag = true;
                break;
            }
            temp = temp.next;//temp後移進行遍歷
        }
        //判斷flag
        if (flag){
            //找到,可以刪除
            //相當於把需要刪除的節點排除出去了
            temp.pre.next = temp.next;
            if (temp.next != null) {
                //代碼有弊端,然後是最後一個節點,就不需要執行下面這句話,不然會空指針異
                temp.next.pre = temp.pre;
            }
        }else{
            System.out.printf("要刪除的%d節點不存在",no);
        }
    }
}

//定義一個HeroNode2,每個HeroNode對象就是一個節點
class HeroNode2{
    public int no;
    public String name;
    public String nickName;
    public HeroNode2 next;//指向下一個節點,默認爲null
    public HeroNode2 pre;//指向前一個節點,默認爲null
    //構造器
    public HeroNode2(int no,String name,String nickName){
        this.no = no;
        this.name = name;
        this.nickName = nickName;
    }
    //爲了顯示方法,我們重新toString
    @Override
    public String toString() {
        return "[HeroNode2{" +
                "no=" + no +
                ", name='" + name + '\'' +
                ", nickName='" + nickName + "]";
    }
}

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

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