链表有环是什么意思_互联网大厂offer收割之单向链表的概念及面试题大全
鏈表是最基本的數據結構,面試官也常常用鏈表來考察面試者的基本能力,而且鏈表相關的操作相對而言比較簡單,也適合考察寫代碼的能力。鏈表的操作也離不開指針,指針又很容易導致出錯。綜合多方面的原因,鏈表題目在面試中占據著很重要的地位。
1. 單向鏈表的定義
想必大家對數組都非常熟悉,數組在存儲空間(內存)上是連續的。因此,我們可以根據偏移量輕易的找到數組中的數據。但數組最大的問題是大小是固定的,很多場景是無法預判需要的空間大小的。
1.1 什么是單向鏈表
鏈表也是一種線性數據結構,但它最大的優勢是可以動態的調整大小。這樣,我們再也不用擔心應該分配多少空間了。
鏈表是一種物理存儲單元上非連續、非順序的存儲結構,元素的邏輯順序是通過鏈表中的指針鏈接次序實現的鏈表在日常開發中通常通過數據結構和指針的方式實現,其中包含一個本數據結構的next指針,用于指向下一個元素,這樣指下去,就形成了一個單向鏈表。如下是數據結構的定義:
struct list_node {void *data; /* 存儲的數據,通過void指針,可以適配多種數據類型 */struct list_node *next; /* 指向下一個節點,如果為尾節點則指向NULL */ };為了便于鏈表的管理和使用,我們在實際定義的時候通常還會定義個專門的鏈表頭,鏈表頭的定義如下:
struct list {int size;void (*print_node)(void *data);struct list_node *head;struct list_node *tail; };通過增加一個鏈表頭可以方便鏈表的管理,同時通過增加的元數據可以很方便的得到一些鏈表的信息,從而提高效率。這樣,整個鏈表的結構大概如圖1所示。
1.2 單向鏈表的接口
單向鏈表最主要的接口就是初始化、插入元素和刪除元素等操作了。當然,為了方便使用,還有返回鏈表頭元素,鏈表尾元素和鏈表大小等等。我們這里先看一下幾個主要的函數接口。
/* 初始化鏈表 */ void list_init(struct list *list, void (*print_node)(void *data)); /* 向鏈表中添加一個元素,其中node為插入的位置,也就是插到該元素的后面,如果node為NULL則插到首節點。 */ 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);下面我們給出插入操作的代碼實現,其它操作類似,也比較簡單,這里就不羅列代碼了。具體可以參考本文的配套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. 單向鏈表的算法(面試題)
關于單向鏈表的面試題很多,我們這里盡量的都收集過來。目前有些復雜的沒有答案,但我們后續會陸續寫文章將答案收集起來。
2.1 求單鏈表中結點的個數
這個題目是比較簡單的,基本做法就是對單向鏈表進行遍歷。在進行遍歷的時候有一個計數的變量,每遍歷一個節點,計數增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 單鏈表反轉 (leetcode 206)
將鏈表中的節點指向反過來,比如原來的指向為1->2->3->4->5,那么反轉后為5->4->3->2->1。鏈表反轉其實是調整節點的next指針的指向。具體如圖所示。
2.3 截取出單鏈表中的后K個結點(k>0)
2.4 判斷一個單鏈表中是否有環(若帶環,求環的長度和入口點)
2.5 去除有序鏈表中的重復元素(leetcode 83)
給定一個有序的鏈表,刪除所有重復的元素,保證每個元素在鏈表中只出現一次。
2.6 合并兩個排好序的鏈表(leetcode 21)
2.7 鏈表的中間節點(leetcode 876)
給定一個帶有頭結點 head 的非空單鏈表,返回鏈表的中間結點。如果有兩個中間結點,則返回第二個中間結點。
輸入:[1,2,3,4,5] 輸出:此列表中的結點 3 (序列化形式:[3,4,5]) 返回的結點值為 3 。 (測評系統對該結點序列化表述是 [3,4,5])。2.7 刪除鏈表中的節點 (leetcode 237)
請編寫一個函數,使其可以刪除某個鏈表中給定的(非末尾)節點。也就是你僅知道要求被刪除的節點。
輸入: head = [4,5,1,9], node = 5 輸出: [4,1,9]解釋: 給定你鏈表中值為 5 的第二個節點,那么在調用了你的函數之后,該鏈表應變為 4 -> 1 -> 9.
鏈表至少包含兩個節點。 鏈表中所有節點的值都是唯一的。 給定的節點為非末尾節點并且一定是鏈表中的一個有效節點。 不要從你的函數中返回任何結果。2.8 刪除鏈表的倒數第N個節點(leetcode 19)
給定一個鏈表: 1->2->3->4->5, 和 n = 2. 當刪除了倒數第二個節點后,鏈表變為 1->2->3->5.
2.9 刪除鏈表中的節點(leetcode 203)
題目 刪除鏈表中等于給定值 val 的所有節點。 示例
輸入: 1->2->6->3->4->5->6, val = 6 輸出: 1->2->3->4->52.10 約瑟夫環
約瑟夫環(約瑟夫問題)是一個數學的應用問題:已知n個人(以編號1,2,3…n分別表示)圍坐在一張圓桌周圍。從編號為k的人開始報數,數到m的那個人出列;他的下一個人又從1開始報數,數到m的那個人又出列;依此規律重復下去,直到圓桌周圍的人全部出列。通常解決這類問題時我們把編號從0~n-1,最后結果+1即為原問題的解。
2.11 遍歷一次,刪除倒數第 k 個結點(k從1開始),不能用替換刪除法
2.12 將鏈表后k個節點移到鏈表頭
給一個鏈表和整數k,將后k個節點移到鏈表頭。
輸入: 1->2->3->4->5->NULL , k =2, 輸出: 4->5->1->2->3->NULL.2.13 逆序打印單鏈表
2.14 不允許遍歷鏈表, 在 pos之前插入
2.15 單鏈表的冒泡排序
2.16 旋轉單鏈表
題目:給定一個鏈表,旋轉鏈表,使得每個節點向右移動k個位置,其中k是一個非負數。
輸入: 1->2->3->4->5->NULL 給定值 k = 2, 輸出: 4->5->1->2->3->NULL.2.17 劃分鏈表
題目 : 按某個給定值將鏈表劃分為左邊小于這個值,右邊大于這個值的新鏈表 如一個鏈表 為 1 -> 4 -> 5 -> 2 給定一個數 3 則劃分后的鏈表為 1-> 2 -> 4 -> 5
2.18 鏈表相加求和
題目: 假設鏈表中每一個節點的值都在 0-9 之間,那么鏈表整體可以代表一個整數。 例如: 9->3->7 可以代表 937 給定兩個這樣的鏈表,頭節點為 head1 head2 生成鏈表相加的新鏈表。 如 9->3->7 和 6 -> 3 生成的新鏈表應為 1 -> 0 -> 0 -> 0
2.19 重排鏈表
題目 給定一個單鏈表L: L0→L1→…→Ln-1→Ln, 重新排列后為 L0→Ln→L1→Ln-1→L2→Ln-2→… 要求必須在不改變節點值的情況下進行原地操作。
總結
以上是生活随笔為你收集整理的链表有环是什么意思_互联网大厂offer收割之单向链表的概念及面试题大全的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 唯一标识 微信小程序_微信小程序获取用户
- 下一篇: 什么是热钱 又称投机性短期资本