單向鏈表及面試題大全

鏈表是最基本的數(shù)據(jù)結(jié)構(gòu)闸迷,面試官也常常用鏈表來考察面試者的基本能力士败,而且鏈表相關(guān)的操作相對而言比較簡單闯两,也適合考察寫代碼的能力。鏈表的操作也離不開指針谅将,指針又很容易導(dǎo)致出錯生蚁。綜合多方面的原因,鏈表題目在面試中占據(jù)著很重要的地位戏自。

1. 單向鏈表的定義

想必大家對數(shù)組都非常熟悉,數(shù)組在存儲空間(內(nèi)存)上是連續(xù)的伤锚。因此擅笔,我們可以根據(jù)偏移量輕易的找到數(shù)組中的數(shù)據(jù)。但數(shù)組最大的問題是大小是固定的屯援,很多場景是無法預(yù)判需要的空間大小的猛们。

1.1 什么是單向鏈表

鏈表也是一種線性數(shù)據(jù)結(jié)構(gòu),但它最大的優(yōu)勢是可以動態(tài)的調(diào)整大小狞洋。這樣弯淘,我們再也不用擔(dān)心應(yīng)該分配多少空間了。

鏈表是一種物理存儲單元上非連續(xù)吉懊、非順序的存儲結(jié)構(gòu)庐橙,元素的邏輯順序是通過鏈表中的指針鏈接次序?qū)崿F(xiàn)的

鏈表在日常開發(fā)中通常通過數(shù)據(jù)結(jié)構(gòu)和指針的方式實現(xiàn),其中包含一個本數(shù)據(jù)結(jié)構(gòu)的next指針借嗽,用于指向下一個元素态鳖,這樣指下去,就形成了一個單向鏈表恶导。如下是數(shù)據(jù)結(jié)構(gòu)的定義:

struct list_node
{
        void *data;             /* 存儲的數(shù)據(jù)浆竭,通過void指針,可以適配多種數(shù)據(jù)類型 */
        struct list_node *next; /* 指向下一個節(jié)點,如果為尾節(jié)點則指向NULL */
};

為了便于鏈表的管理和使用邦泄,我們在實際定義的時候通常還會定義個專門的鏈表頭删窒,鏈表頭的定義如下:

struct list
{
        int size;
        void (*print_node)(void *data);
        struct list_node *head;
        struct list_node *tail;
};

通過增加一個鏈表頭可以方便鏈表的管理,同時通過增加的元數(shù)據(jù)可以很方便的得到一些鏈表的信息顺囊,從而提高效率肌索。這樣,整個鏈表的結(jié)構(gòu)大概如圖1所示包蓝。

圖1 單向鏈表示意圖

1.2 單向鏈表的接口

單向鏈表最主要的接口就是初始化驶社、插入元素和刪除元素等操作了。當(dāng)然测萎,為了方便使用亡电,還有返回鏈表頭元素,鏈表尾元素和鏈表大小等等硅瞧。我們這里先看一下幾個主要的函數(shù)接口份乒。

/*  初始化鏈表 */
void list_init(struct list *list, void (*print_node)(void *data));
/* 向鏈表中添加一個元素,其中node為插入的位置腕唧,也就是
   插到該元素的后面或辖,如果node為NULL則插到首節(jié)點。  */
int list_insert_next(struct list *list, struct list_node *node, void *data);
int list_rem_next(struct list *list, struct list_node *node, void **data);

下面我們給出插入操作的代碼實現(xiàn)枣接,其它操作類似颂暇,也比較簡單,這里就不羅列代碼了但惶。具體可以參考本文的配套github庫耳鸯。

int list_insert_next(struct list *list, 
                     struct list_node *node,
                     void *data)
{
        struct list_node *new_node;

        if (NULL == list) {
                return -1;
        }       

        new_node = (struct list_node*)malloc(sizeof(struct list_node));
        if (NULL == new_node) {
                return -1;
        }

        new_node->data = data;
        if (NULL == node) {
                if (list_size(list) == 0)
                        list->tail = new_node;
                new_node->next = list->head;
                list->head = new_node;          
        } else {
                if (NULL == node->next) {
                        list->tail = new_node;
                }
                new_node->next = node->next;
                node->next = new_node;
        }

        list->size ++;
        return 0;
}

2. 單向鏈表的算法(面試題)

關(guān)于單向鏈表的面試題很多,我們這里盡量的都收集過來膀曾。目前有些復(fù)雜的沒有答案县爬,但我們后續(xù)會陸續(xù)寫文章將答案收集起來。

2.1 求單鏈表中結(jié)點的個數(shù)

這個題目是比較簡單的添谊,基本做法就是對單向鏈表進(jìn)行遍歷财喳。在進(jìn)行遍歷的時候有一個計數(shù)的變量,每遍歷一個節(jié)點斩狱,計數(shù)增1耳高,直到完成鏈表的遍歷。

int list_node_count(struct list *list)
{
        int ret = 0;
        struct list_node *cur_node;
        /* 注意list指針非法的情況 */
        if (NULL == list) {
                return ret;
        }   

        cur_node = list->head;
        while (cur_node) {
                ret ++; 
                cur_node = cur_node->next;
        }   
        return ret;
}

2.2 單鏈表反轉(zhuǎn) (leetcode 206)

將鏈表中的節(jié)點指向反過來喊废,比如原來的指向為1->2->3->4->5祝高,那么反轉(zhuǎn)后為5->4->3->2->1。鏈表反轉(zhuǎn)其實是調(diào)整節(jié)點的next指針的指向污筷。具體如圖所示工闺。


圖2 鏈表反轉(zhuǎn)示意圖

2.3 截取出單鏈表中的后K個結(jié)點(k>0)

2.4 判斷一個單鏈表中是否有環(huán)(若帶環(huán)乍赫,求環(huán)的長度和入口點)

2.5 去除有序鏈表中的重復(fù)元素(leetcode 83)

給定一個有序的鏈表,刪除所有重復(fù)的元素陆蟆,保證每個元素在鏈表中只出現(xiàn)一次雷厂。

2.6 合并兩個排好序的鏈表(leetcode 21)

2.7 鏈表的中間節(jié)點(leetcode 876)

給定一個帶有頭結(jié)點 head 的非空單鏈表,返回鏈表的中間結(jié)點叠殷。如果有兩個中間結(jié)點改鲫,則返回第二個中間結(jié)點。

輸入:[1,2,3,4,5]
輸出:此列表中的結(jié)點 3 (序列化形式:[3,4,5])
返回的結(jié)點值為 3 林束。 (測評系統(tǒng)對該結(jié)點序列化表述是 [3,4,5])像棘。

2.7 刪除鏈表中的節(jié)點 (leetcode 237)

請編寫一個函數(shù),使其可以刪除某個鏈表中給定的(非末尾)節(jié)點壶冒。也就是你僅知道要求被刪除的節(jié)點缕题。

輸入: head = [4,5,1,9], node = 5
輸出: [4,1,9]

解釋: 給定你鏈表中值為 5 的第二個節(jié)點,那么在調(diào)用了你的函數(shù)之后胖腾,該鏈表應(yīng)變?yōu)?4 -> 1 -> 9.

鏈表至少包含兩個節(jié)點烟零。
鏈表中所有節(jié)點的值都是唯一的。
給定的節(jié)點為非末尾節(jié)點并且一定是鏈表中的一個有效節(jié)點咸作。
不要從你的函數(shù)中返回任何結(jié)果锨阿。

2.8 刪除鏈表的倒數(shù)第N個節(jié)點(leetcode 19)

給定一個鏈表: 1->2->3->4->5, 和 n = 2.
當(dāng)刪除了倒數(shù)第二個節(jié)點后,鏈表變?yōu)?1->2->3->5.

2.9 刪除鏈表中的節(jié)點(leetcode 203)

題目
刪除鏈表中等于給定值 val 的所有節(jié)點记罚。
示例

輸入: 1->2->6->3->4->5->6, val = 6
輸出: 1->2->3->4->5

2.10 約瑟夫環(huán)

約瑟夫環(huán)(約瑟夫問題)是一個數(shù)學(xué)的應(yīng)用問題:已知n個人(以編號1墅诡,2,3…n分別表示)圍坐在一張圓桌周圍桐智。從編號為k的人開始報數(shù)书斜,數(shù)到m的那個人出列;他的下一個人又從1開始報數(shù),數(shù)到m的那個人又出列;依此規(guī)律重復(fù)下去酵使,直到圓桌周圍的人全部出列。通常解決這類問題時我們把編號從0~n-1焙糟,最后結(jié)果+1即為原問題的解口渔。

2.11 遍歷一次,刪除倒數(shù)第 k 個結(jié)點(k從1開始)穿撮,不能用替換刪除法

2.12 將鏈表后k個節(jié)點移到鏈表頭

給一個鏈表和整數(shù)k缺脉,將后k個節(jié)點移到鏈表頭。

輸入: 1->2->3->4->5->NULL , k =2,
輸出: 4->5->1->2->3->NULL.

2.13 逆序打印單鏈表

2.14 不允許遍歷鏈表, 在 pos之前插入

2.15 單鏈表的冒泡排序

2.16 旋轉(zhuǎn)單鏈表

題目:給定一個鏈表悦穿,旋轉(zhuǎn)鏈表攻礼,使得每個節(jié)點向右移動k個位置,其中k是一個非負(fù)數(shù)栗柒。

輸入: 1->2->3->4->5->NULL 給定值 k = 2,
輸出: 4->5->1->2->3->NULL.

2.17 劃分鏈表

題目 : 按某個給定值將鏈表劃分為左邊小于這個值礁扮,右邊大于這個值的新鏈表 如一個鏈表 為 1 -> 4 -> 5 -> 2 給定一個數(shù) 3 則劃分后的鏈表為 1-> 2 -> 4 -> 5

2.18 鏈表相加求和

題目: 假設(shè)鏈表中每一個節(jié)點的值都在 0-9 之間,那么鏈表整體可以代表一個整數(shù)。
例如: 9->3->7 可以代表 937
給定兩個這樣的鏈表太伊,頭節(jié)點為 head1 head2 生成鏈表相加的新鏈表雇锡。
如 9->3->7 和 6 -> 3 生成的新鏈表應(yīng)為 1 -> 0 -> 0 -> 0

2.19 重排鏈表

題目 給定一個單鏈表L: L0→L1→…→Ln-1→Ln, 重新排列后為 L0→Ln→L1→Ln-1→L2→Ln-2→… 要求必須在不改變節(jié)點值的情況下進(jìn)行原地操作。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末僚焦,一起剝皮案震驚了整個濱河市锰提,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌芳悲,老刑警劉巖立肘,帶你破解...
    沈念sama閱讀 206,968評論 6 482
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異名扛,居然都是意外死亡谅年,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,601評論 2 382
  • 文/潘曉璐 我一進(jìn)店門罢洲,熙熙樓的掌柜王于貴愁眉苦臉地迎上來踢故,“玉大人,你說我怎么就攤上這事惹苗〉罱希” “怎么了?”我有些...
    開封第一講書人閱讀 153,220評論 0 344
  • 文/不壞的土叔 我叫張陵桩蓉,是天一觀的道長淋纲。 經(jīng)常有香客問我,道長院究,這世上最難降的妖魔是什么洽瞬? 我笑而不...
    開封第一講書人閱讀 55,416評論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮业汰,結(jié)果婚禮上伙窃,老公的妹妹穿的比我還像新娘。我一直安慰自己样漆,他們只是感情好为障,可當(dāng)我...
    茶點故事閱讀 64,425評論 5 374
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著放祟,像睡著了一般鳍怨。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上跪妥,一...
    開封第一講書人閱讀 49,144評論 1 285
  • 那天鞋喇,我揣著相機(jī)與錄音,去河邊找鬼眉撵。 笑死侦香,一個胖子當(dāng)著我的面吹牛落塑,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播鄙皇,決...
    沈念sama閱讀 38,432評論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼芜赌,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了伴逸?” 一聲冷哼從身側(cè)響起缠沈,我...
    開封第一講書人閱讀 37,088評論 0 261
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎错蝴,沒想到半個月后洲愤,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,586評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡顷锰,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,028評論 2 325
  • 正文 我和宋清朗相戀三年柬赐,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片官紫。...
    茶點故事閱讀 38,137評論 1 334
  • 序言:一個原本活蹦亂跳的男人離奇死亡肛宋,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出束世,到底是詐尸還是另有隱情酝陈,我是刑警寧澤,帶...
    沈念sama閱讀 33,783評論 4 324
  • 正文 年R本政府宣布毁涉,位于F島的核電站沉帮,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏贫堰。R本人自食惡果不足惜穆壕,卻給世界環(huán)境...
    茶點故事閱讀 39,343評論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望其屏。 院中可真熱鬧喇勋,春花似錦、人聲如沸偎行。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,333評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽睦优。三九已至,卻和暖如春壮不,著一層夾襖步出監(jiān)牢的瞬間汗盘,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,559評論 1 262
  • 我被黑心中介騙來泰國打工询一, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留隐孽,地道東北人癌椿。 一個月前我還...
    沈念sama閱讀 45,595評論 2 355
  • 正文 我出身青樓,卻偏偏與公主長得像菱阵,于是被迫代替她去往敵國和親踢俄。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 42,901評論 2 345

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