鏈表

1.鏈表(Linked List)介紹

鏈表是有序的列表,但是它在內(nèi)存中是存儲如下


小結(jié)上圖:
1. 鏈表是以節(jié)點的方式來存儲,是鏈?zhǔn)酱鎯?/strong>
2. 每個節(jié)點包含 data 域, next 域:指向下一個節(jié)點.
3. 如圖:發(fā)現(xiàn)鏈表的各個節(jié)點不一定是連續(xù)存儲.
4. 鏈表分帶頭節(jié)點的鏈表沒有頭節(jié)點的鏈表,根據(jù)實際的需求來確定

  • 單鏈表(帶頭結(jié)點) 邏輯結(jié)構(gòu)示意圖如下



2.單鏈表的應(yīng)用實例

使用帶 head 頭的單向鏈表實現(xiàn) –水滸英雄排行榜管理完成對英雄人物的增刪改查操作顷啼, 注: 刪除和修改,查找

  1. 第一種方法在添加英雄時,直接添加到鏈表的尾部
    思路分析示意圖:


  2. 第二種方式在添加英雄時缩焦,根據(jù)排名將英雄插入到指定位置(如果有這個排名孽糖,則添加失敗皮官,并給出提示)
    思路的分析示意圖:
  3. 修改節(jié)點功能
    思路(1) 先找到該節(jié)點,通過遍歷愿吹,(2) temp.name = newHeroNode.name ; temp.nickname= newHeroNode.nickname
  1. 刪除節(jié)點
    思路分析的示意圖:


  1. 完成的代碼演示:
public class SingleLinkedListDemo {
    public static void main(String[] args) {
        //進(jìn)行測試
        //先創(chuàng)建節(jié)點
        HeroNode hero1 = new HeroNode(1, "宋江", "及時雨");
        HeroNode hero2 = new HeroNode(2, "盧俊義", "玉麒麟");
        HeroNode hero3 = new HeroNode(3, "吳用", "智多星");
        HeroNode hero4 = new HeroNode(4, "林沖", "豹子頭");
        //創(chuàng)建要給鏈表
        SingleLinkedList singleLinkedList = new SingleLinkedList();
        //加入
        // singleLinkedList.add(hero1);
        // singleLinkedList.add(hero4);
        // singleLinkedList.add(hero2);
        // singleLinkedList.add(hero3);
        //加入按照編號的順序
        singleLinkedList.addByOrder(hero1);
        singleLinkedList.addByOrder(hero4);
        singleLinkedList.addByOrder(hero2);
        singleLinkedList.addByOrder(hero3);
        //顯示一把
        singleLinkedList.list();
        //測試修改節(jié)點的代碼
        HeroNode newHeroNode = new HeroNode(2, "小盧", "玉麒麟~~");
        singleLinkedList.update(newHeroNode);
        System.out.println("修改后的鏈表情況~~");
        singleLinkedList.list();
        //刪除一個節(jié)點
        singleLinkedList.del(1);
        singleLinkedList.del(4);
        System.out.println("刪除后的鏈表情況~~");
        singleLinkedList.list();
    }
}

//定義 SingleLinkedList 管理我們的英雄
class SingleLinkedList {
    //先初始化一個頭節(jié)點, 頭節(jié)點不要動, 不存放具體的數(shù)據(jù)
    private HeroNode head = new HeroNode(0, "", "");

    //添加節(jié)點到單向鏈表
    //思路,當(dāng)不考慮編號順序時
    //1. 找到當(dāng)前鏈表的最后節(jié)點
    //2. 將最后這個節(jié)點的 next 指向 新的節(jié)點
    public void add(HeroNode heroNode) {
        //因為 head 節(jié)點不能動惜姐,因此我們需要一個輔助遍歷 temp
        HeroNode temp = head;
        //遍歷鏈表洗搂,找到最后
        while (true) {
            //找到鏈表的最后
            if (temp.next == null) {//
                break;
            }
            //如果沒有找到最后, 將將 temp 后移
            temp = temp.next;
        }
        //當(dāng)退出 while 循環(huán)時,temp 就指向了鏈表的最后
        //將最后這個節(jié)點的 next 指向 新的節(jié)點
        temp.next = heroNode;
    }

    //第二種方式在添加英雄時载弄,根據(jù)排名將英雄插入到指定位置
    //(如果有這個排名耘拇,則添加失敗,并給出提示)
    public void addByOrder(HeroNode heroNode) {
        //因為頭節(jié)點不能動宇攻,因此我們?nèi)匀煌ㄟ^一個輔助指針(變量)來幫助找到添加的位置
        //因為單鏈表惫叛,因為我們找的 temp 是位于 添加位置的前一個節(jié)點,否則插入不了
        HeroNode temp = head;
        boolean flag = false; // flag 標(biāo)志添加的編號是否存在逞刷,默認(rèn)為 false
        while (true) {
            if (temp.next == null) {//說明 temp 已經(jīng)在鏈表的最后
                break; //
            }
            if (temp.next.no > heroNode.no) { //位置找到嘉涌,就在 temp 的后面插入
                break;
            } else if (temp.next.no == heroNode.no) {//說明希望添加的 heroNode 的編號已然存在
                flag = true; //說明編號存在
                break;
            }
            temp = temp.next; //后移,遍歷當(dāng)前鏈表
        }
        //判斷 flag 的值
        if (flag) { //不能添加夸浅,說明編號存在
            System.out.printf("準(zhǔn)備插入的英雄的編號 %d 已經(jīng)存在了, 不能加入\n", heroNode.no);
        } else {
            //插入到鏈表中, temp 的后面
            heroNode.next = temp.next;
            temp.next = heroNode;
        }
    }

    //修改節(jié)點的信息, 根據(jù) no 編號來修改仑最,即 no 編號不能改. //說明
    //1. 根據(jù) newHeroNode 的 no 來修改即可
    public void update(HeroNode newHeroNode) {
        //判斷是否空
        if (head.next == null) {
            System.out.println("鏈表為空~");
            return;
        }
        //找到需要修改的節(jié)點, 根據(jù) no 編號
        //定義一個輔助變量
        HeroNode temp = head.next;
        boolean flag = false; //表示是否找到該節(jié)點
        while (true) {
            if (temp == null) {
                break; //已經(jīng)遍歷完鏈表
            }
            if (temp.no == newHeroNode.no) {
                //找到
                flag = true;
                break;
            }
            temp = temp.next;
        }
        //根據(jù) flag 判斷是否找到要修改的節(jié)點
        if (flag) {
            temp.name = newHeroNode.name;
            temp.nickname = newHeroNode.nickname;
        } else { //沒有找到
            System.out.printf("沒有找到 編號 %d 的節(jié)點,不能修改\n", newHeroNode.no);
        }
    }

    //刪除節(jié)點
    //思路
    //1. head 不能動帆喇,因此我們需要一個 temp 輔助節(jié)點找到待刪除節(jié)點的前一個節(jié)點
    //2. 說明我們在比較時警医,是 temp.next.no 和 需要刪除的節(jié)點的 no 比較
    public void del(int no) {
        HeroNode temp = head;
        boolean flag = false; // 標(biāo)志是否找到待刪除節(jié)點的
        while (true) {
            if (temp.next == null) { //已經(jīng)到鏈表的最后
                break;
            }
            if (temp.next.no == no) {
                //找到的待刪除節(jié)點的前一個節(jié)點 temp
                flag = true;
                break;
            }
            temp = temp.next; //temp 后移,遍歷
        }
        //判斷 flag
        if (flag) { //找到
            //可以刪除
            temp.next = temp.next.next;
        } else {
            System.out.printf("要刪除的 %d 節(jié)點不存在\n", no);
        }
    }

    //顯示鏈表[遍歷]
    public void list() {
        //判斷鏈表是否為空
        if (head.next == null) {
            System.out.println("鏈表為空");
            return;
        }
        //因為頭節(jié)點坯钦,不能動预皇,因此我們需要一個輔助變量來遍歷
        HeroNode temp = head.next;
        while (true) {
            //判斷是否到鏈表最后
            if (temp == null) {
                break;
            }
            //輸出節(jié)點的信息
            System.out.println(temp);
            //將 temp 后移, 一定小心
            temp = temp.next;
        }
    }
}

//定義 HeroNode 婉刀, 每個 HeroNode 對象就是一個節(jié)點
class HeroNode {
    public int no;
    public String name;
    public String nickname;
    public HeroNode next; //指向下一個節(jié)點

    //構(gòu)造器
    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 + "]";
    }
}

單鏈表常見面試題

  1. 求單鏈表中有效節(jié)點的個數(shù)
    代碼如下:
//方法:獲取到單鏈表的節(jié)點的個數(shù)(如果是帶頭結(jié)點的鏈表,需求不統(tǒng)計頭節(jié)點)
/**
 * @param head 鏈表的頭節(jié)點
 * @return 返回的就是有效節(jié)點的個數(shù)
 */
public static int getLength(HeroNode head){
        if(head.next==null){ //空鏈表
        return 0;
        }
        int length=0;
        //定義一個輔助的變量, 這里我們沒有統(tǒng)計頭節(jié)點
        HeroNode cur=head.next;
        while(cur!=null){
        length++;
        cur=cur.next; //遍歷
        }
        return length;
        }
  1. 查找單鏈表中的倒數(shù)第 k 個結(jié)點
    代碼如下:
//查找單鏈表中的倒數(shù)第 k 個結(jié)點 
//思路
//1. 編寫一個方法突颊,接收 head 節(jié)點鲁豪,同時接收一個 index
//2. index 表示是倒數(shù)第 index 個節(jié)點
//3. 先把鏈表從頭到尾遍歷潘悼,得到鏈表的總的長度 getLength
//4. 得到 size 后,我們從鏈表的第一個開始遍歷 (size-index)個爬橡,就可以得到
//5. 如果找到了挥等,則返回該節(jié)點,否則返回 nulll
public static HeroNode findLastIndexNode(HeroNode head, int index) {
        //判斷如果鏈表為空堤尾,返回 null
        if(head.next == null) {
        return null;//沒有找到
        }
        //第一個遍歷得到鏈表的長度(節(jié)點個數(shù))
        int size = getLength(head);
        //第二次遍歷 size-index 位置肝劲,就是我們倒數(shù)的第 K 個節(jié)點
        //先做一個 index 的校驗
        if(index <=0 || index > size) {
        return null;
        }
        //定義給輔助變量, for 循環(huán)定位到倒數(shù)的 index
        HeroNode cur = head.next; //3 // 3 - 1 = 2
        for(int i =0; i< size - index; i++) {
        cur = cur.next;
        }
        return cur;
        }
  1. 單鏈表的反轉(zhuǎn)
  • 思路分析圖解



  • 代碼實現(xiàn)
//將單鏈表反轉(zhuǎn)
public static void reversetList(HeroNode head) {
        //如果當(dāng)前鏈表為空郭宝,或者只有一個節(jié)點辞槐,無需反轉(zhuǎn),直接返回
        if(head.next == null || head.next.next == null) {
        return ;
        }
        //定義一個輔助的指針(變量)粘室,幫助我們遍歷原來的鏈表
        HeroNode cur = head.next;
        HeroNode next = null;// 指向當(dāng)前節(jié)點[cur]的下一個節(jié)點
        HeroNode reverseHead = new HeroNode(0, "", "");
        //遍歷原來的鏈表榄檬,每遍歷一個節(jié)點,就將其取出衔统,并放在新的鏈表 reverseHead 的最前端
        while(cur != null) {
        next = cur.next;//先暫時保存當(dāng)前節(jié)點的下一個節(jié)點鹿榜,因為后面需要使用
        cur.next = reverseHead.next;//將 cur 的下一個節(jié)點指向新的鏈表的最前端
        reverseHead.next = cur; //將 cur 連接到新的鏈表上
        cur = next;//讓 cur 后移
        }
        //將 head.next 指向 reverseHead.next , 實現(xiàn)單鏈表的反轉(zhuǎn)
        head.next = reverseHead.next;
        }
  1. 從尾到頭打印單鏈表
  • 思路分析圖解
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市锦爵,隨后出現(xiàn)的幾起案子舱殿,更是在濱河造成了極大的恐慌,老刑警劉巖险掀,帶你破解...
    沈念sama閱讀 222,378評論 6 516
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件沪袭,死亡現(xiàn)場離奇詭異,居然都是意外死亡樟氢,警方通過查閱死者的電腦和手機冈绊,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,970評論 3 399
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來埠啃,“玉大人死宣,你說我怎么就攤上這事〔昕” “怎么了毅该?”我有些...
    開封第一講書人閱讀 168,983評論 0 362
  • 文/不壞的土叔 我叫張陵,是天一觀的道長叹螟。 經(jīng)常有香客問我鹃骂,道長,這世上最難降的妖魔是什么罢绽? 我笑而不...
    開封第一講書人閱讀 59,938評論 1 299
  • 正文 為了忘掉前任,我火速辦了婚禮静盅,結(jié)果婚禮上良价,老公的妹妹穿的比我還像新娘寝殴。我一直安慰自己,他們只是感情好明垢,可當(dāng)我...
    茶點故事閱讀 68,955評論 6 398
  • 文/花漫 我一把揭開白布蚣常。 她就那樣靜靜地躺著,像睡著了一般痊银。 火紅的嫁衣襯著肌膚如雪抵蚊。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,549評論 1 312
  • 那天溯革,我揣著相機與錄音贞绳,去河邊找鬼。 笑死致稀,一個胖子當(dāng)著我的面吹牛冈闭,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播抖单,決...
    沈念sama閱讀 41,063評論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼萎攒,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了矛绘?” 一聲冷哼從身側(cè)響起耍休,我...
    開封第一講書人閱讀 39,991評論 0 277
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎货矮,沒想到半個月后羹应,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,522評論 1 319
  • 正文 獨居荒郊野嶺守林人離奇死亡次屠,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,604評論 3 342
  • 正文 我和宋清朗相戀三年园匹,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片劫灶。...
    茶點故事閱讀 40,742評論 1 353
  • 序言:一個原本活蹦亂跳的男人離奇死亡裸违,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出本昏,到底是詐尸還是另有隱情供汛,我是刑警寧澤,帶...
    沈念sama閱讀 36,413評論 5 351
  • 正文 年R本政府宣布涌穆,位于F島的核電站怔昨,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏宿稀。R本人自食惡果不足惜趁舀,卻給世界環(huán)境...
    茶點故事閱讀 42,094評論 3 335
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望祝沸。 院中可真熱鬧矮烹,春花似錦越庇、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,572評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至仁期,卻和暖如春桑驱,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背跛蛋。 一陣腳步聲響...
    開封第一講書人閱讀 33,671評論 1 274
  • 我被黑心中介騙來泰國打工熬的, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人问芬。 一個月前我還...
    沈念sama閱讀 49,159評論 3 378
  • 正文 我出身青樓悦析,卻偏偏與公主長得像,于是被迫代替她去往敵國和親此衅。 傳聞我的和親對象是個殘疾皇子强戴,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,747評論 2 361

推薦閱讀更多精彩內(nèi)容