數(shù)據結構與算法之鏈表(三)單鏈表的常用操作

引言

在上篇文章數(shù)據結構與算法之鏈表(二)單鏈表的基本實現(xiàn)中我們學習了單鏈表的基本概念,本篇我們在此基礎之上研究單鏈表相對復雜的操作(也是面試中經常被問到的經典問題,這是其次亮蛔,重點是學習思想)寺晌。本文的代碼都是基于上篇單鏈表而實現(xiàn)的丧靡。

單鏈表的逆序實現(xiàn)

整體思路:鏈表的逆序過程必然會將鏈表分割成兩個部分:原鏈表和已經逆序好的鏈表,那么逆序操作的起始點可以從表頭或者表尾開始综膀;

單鏈表的逆序實現(xiàn)(表頭開始)

1.思路:既然原始單鏈表被分割成兩部分,加入當前需要將節(jié)點curNode加入逆序鏈表,必然需要記錄p的后繼節(jié)點以便下個節(jié)點的逆序操作葛躏,還需要一個節(jié)點reversHead指向已經逆序的鏈表,引入nextNode保存curNode下個操作節(jié)點;這樣每一次針對curNode的逆序操作如下:
1>操作節(jié)點后繼指向逆序列表頭(操作節(jié)點做斷裂操作);
2>逆序列表頭更新為當前操作節(jié)點(操作節(jié)點做連接逆序鏈表操作)澈段;
3> 本次逆序操作結束,curNode指向下個節(jié)點。


逆序操作流程.png

代碼如下:

    /**
     * 單鏈表的逆序操作(從表頭非遞歸)
     */
    public void reverseList() {
        //逆序操作只有在2個元素以上才有效
        if (isEmpty() || headNode.next == null) {
            return;
        }
        SNode<T> curNode = headNode;//當前要逆序操作的節(jié)點
        SNode<T> reversHead = null;//當前的逆序頭節(jié)點
        while (curNode != null) {
            SNode<T> nextNode = curNode.next;//保存下個操作節(jié)點
            curNode.next = reversHead;//操作節(jié)點指向逆序列表頭,做斷裂操作
            reversHead = curNode;//逆序列表頭更新,操作節(jié)點做連接操作
            curNode = nextNode;//下個節(jié)點
        }
        headNode = reversHead;
    }

單鏈表的逆序實現(xiàn)(表尾開始)

思路:從表尾開始逆序舰攒,每次的遞歸操作如下:
1> 遍歷已經逆序好的鏈表到結尾败富,掛載當前操作節(jié)點到逆序鏈表上;
2>掛載的節(jié)點做原鏈表斷開操作;
3>當操作節(jié)點為原鏈表的尾部節(jié)點時摩窃,直接返回該節(jié)點當做逆序鏈表的頭節(jié)點兽叮。代碼如下:

    /**
     * 遞歸逆序鏈表,
     *
     * @param p 當前需要逆序的操作節(jié)點
     * @return 逆序后的鏈表頭節(jié)點
     */
    private SNode<T> reverseNodeRecursion(SNode<T> p) {
        if (p.next == null) {//遞歸結束條件芬骄,從鏈表尾開始逆序操作
            return p;//直接返回尾部節(jié)點當做逆序鏈表的起點
        } else {
            SNode<T> result = reverseNodeRecursion(p.next);
            SNode<T> temp = result;
            //找到當前逆序鏈表的結尾然后把p掛上去
            while (temp.next != null) {
                temp = temp.next;
            }
            temp.next = p;
            p.next = null;//當前節(jié)點已經掛載,則斷開與原鏈表的聯(lián)系
            return result;
        }
    }

查找中間節(jié)點

思路:采用兩個指針:快指針和慢指針鹦聪,快指針移速是慢指針的兩倍账阻,當快指針達到結尾,慢指針正好到達中間位置.

    /**
     * 查找中間節(jié)點,快節(jié)點掃描速度是慢節(jié)點兩倍
     *
     * @return
     */
    public T searchMid() {
        if (isEmpty()) {
            return null;
        }
        SNode<T> slowNode = headNode;
        SNode<T> fastNode = headNode;
        while (fastNode != null && fastNode.next != null && fastNode.next.next != null) {
            slowNode = slowNode.next;
            fastNode = fastNode.next.next;
        }
        return slowNode.data;
    }

查找倒數(shù)第K個元素

思路:采用兩個指針:前指針和后指針泽本,前指針先移動K步淘太,然后同時移動,當前指針到達結尾规丽,則后指針為目標位置蒲牧。

    /**
     * 查找倒數(shù)第K個元素
     *
     * @param k
     * @return
     */
    public T searchBackwardsElement(int k) {
        if (isEmpty()) {
            return null;
        }
        if (k >= size()) {
            return null;
        }
        SNode<T> leftNode = headNode;
        SNode<T> rightNode = leftNode;
        for (int i = 0; i < k; i++) {
            rightNode = rightNode.next;
        }
        //右邊的掃描節(jié)點到結尾
        while (rightNode != null && rightNode.next != null) {
            rightNode = rightNode.next;
            leftNode = leftNode.next;
        }

        return leftNode.data;
    }

基本排序

思路:雙層循環(huán)進行兩兩交換。

   /**
     * 基本排序
     */
    public void sortList() {
        if (isEmpty()) {
            return;
        }
        SNode<T> curNode = headNode;
        while (curNode.next != null) {//大循環(huán)
            //小循環(huán)
            SNode<T> tempNode = curNode.next;
            while (tempNode != null) {
                if (curNode.data.compareTo(tempNode.data) > 0) {
                    T tempData = curNode.data;
                    curNode.data = tempNode.data;
                    tempNode.data = tempData;
                }
                tempNode = tempNode.next;
            }
            curNode = curNode.next;
        }
    }

刪除重復元素

思路:雙層循環(huán)進行刪除元素操作赌莺,注意操作的節(jié)點是當前節(jié)點的后繼節(jié)點造成。

   /**
     * 刪除重復元素,類似排序,需要嵌套遍歷
     */
    public void removeAllDuplicateItems() {
        SNode<T> curNode = headNode;//大循環(huán)
        while (curNode != null) {
            SNode<T> temp = curNode;
            while (temp.next != null) {//由于要做刪除操作雄嚣,所以需要它的前驅晒屎,這里操作節(jié)點為temp.next
                if (temp.next.data.equals(curNode.data)) {//如果相等則做刪除操作
                    //刪除操作
                    temp.next = temp.next.next;//刪除temp.next節(jié)點
                } else {
                    temp = temp.next;//否則下個節(jié)點
                }
            }
            curNode = curNode.next;
        }
    }

遞歸逆序打印

思路:先遞歸調用,再打印當前元素

  /**
     * 遞歸逆序打印
     */
    public void printListReversely() {
        printListReversely(headNode);
    }

    /**
     * 逆序打印元素
     * @param head
     */
    public void printListReversely(SNode<T> head) {
        if (head != null) {
            printListReversely(head.next);
            Log.e("SingleList", head.data.toString());
        }
    }

以上就是單鏈表的常用操作缓升,除了這些鼓鲁,還有一個比較經典的單鏈表尾環(huán)問題,這個問題涉及數(shù)學中的跑道追及問題港谊,限于篇幅骇吭,在下一篇將做全面細致的分析。

?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末歧寺,一起剝皮案震驚了整個濱河市燥狰,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌斜筐,老刑警劉巖龙致,帶你破解...
    沈念sama閱讀 219,427評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異顷链,居然都是意外死亡目代,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,551評論 3 395
  • 文/潘曉璐 我一進店門嗤练,熙熙樓的掌柜王于貴愁眉苦臉地迎上來榛了,“玉大人,你說我怎么就攤上這事煞抬∷螅” “怎么了?”我有些...
    開封第一講書人閱讀 165,747評論 0 356
  • 文/不壞的土叔 我叫張陵革答,是天一觀的道長战坤。 經常有香客問我遮婶,道長,這世上最難降的妖魔是什么湖笨? 我笑而不...
    開封第一講書人閱讀 58,939評論 1 295
  • 正文 為了忘掉前任旗扑,我火速辦了婚禮,結果婚禮上慈省,老公的妹妹穿的比我還像新娘臀防。我一直安慰自己,他們只是感情好边败,可當我...
    茶點故事閱讀 67,955評論 6 392
  • 文/花漫 我一把揭開白布袱衷。 她就那樣靜靜地躺著,像睡著了一般笑窜。 火紅的嫁衣襯著肌膚如雪致燥。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,737評論 1 305
  • 那天排截,我揣著相機與錄音嫌蚤,去河邊找鬼。 笑死断傲,一個胖子當著我的面吹牛脱吱,可吹牛的內容都是我干的。 我是一名探鬼主播认罩,決...
    沈念sama閱讀 40,448評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼箱蝠,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了垦垂?” 一聲冷哼從身側響起宦搬,我...
    開封第一講書人閱讀 39,352評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎劫拗,沒想到半個月后间校,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經...
    沈念sama閱讀 45,834評論 1 317
  • 正文 獨居荒郊野嶺守林人離奇死亡杨幼,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 37,992評論 3 338
  • 正文 我和宋清朗相戀三年撇簿,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片差购。...
    茶點故事閱讀 40,133評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖汉嗽,靈堂內的尸體忽然破棺而出欲逃,到底是詐尸還是另有隱情,我是刑警寧澤饼暑,帶...
    沈念sama閱讀 35,815評論 5 346
  • 正文 年R本政府宣布稳析,位于F島的核電站洗做,受9級特大地震影響,放射性物質發(fā)生泄漏彰居。R本人自食惡果不足惜诚纸,卻給世界環(huán)境...
    茶點故事閱讀 41,477評論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望陈惰。 院中可真熱鬧畦徘,春花似錦、人聲如沸抬闯。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,022評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽溶握。三九已至杯缺,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間睡榆,已是汗流浹背萍肆。 一陣腳步聲響...
    開封第一講書人閱讀 33,147評論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留胀屿,地道東北人匾鸥。 一個月前我還...
    沈念sama閱讀 48,398評論 3 373
  • 正文 我出身青樓,卻偏偏與公主長得像碉纳,于是被迫代替她去往敵國和親勿负。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 45,077評論 2 355

推薦閱讀更多精彩內容

  • 搞懂單鏈表常見面試題 Hello 繼上次的 搞懂基本排序算法劳曹,這個一星期奴愉,我總結了,我所學習和思考的單鏈表基礎知識...
    醒著的碼者閱讀 4,588評論 1 45
  • 1 序 2016年6月25日夜铁孵,帝都锭硼,天下著大雨,拖著行李箱和同學在校門口照了最后一張合照蜕劝,搬離寢室打車去了提前租...
    RichardJieChen閱讀 5,105評論 0 12
  • 代碼GitHub地址 鏈表概述 數(shù)組和鏈表都是線性存儲結構的基礎實現(xiàn)檀头,棧和隊列都是線性存儲結構的應用 數(shù)組優(yōu)缺點 ...
    HikariCP閱讀 1,388評論 0 0
  • 本文內容取自于小甲魚的數(shù)據結構與算法。http://www.reibang.com/p/230e6fde9c75 ...
    阿阿阿阿毛閱讀 2,894評論 0 7
  • 我鄉(xiāng)(一) - 他關閉了應用的界面岖沛,把手機放在一旁暑始。薄荷氣泡飲中彌漫著酒精的氣息。后臺運行的軟件在空氣中為他顯示出...
    非克閱讀 361評論 0 2