常见单链表面试题
面試中經常被問到有關鏈表的問題,現總結如下:(此處的鏈表結構為不帶頭結點的單鏈表)
單鏈表結構
struct ListNode {int val;ListNode *next;ListNode(int val = 0) : val(val), next(NULL) { } };1、尾插法建立單鏈表
ListNode* BuildListTail(int n) {int val;ListNode *head = NULL;ListNode *p = head;for(int i = 0; i < n; ++i) {cin >> val;ListNode *node = new ListNode(val);if(head == NULL) {head = node;p = head;}else {p->next = node;p = p->next;}}return head; }// 輸入1 2 3 4,輸出1 2 3 42、頭插法建立單鏈表
ListNode *BuildListHead(int n) {int val;ListNode *head = NULL;for(int i = 0; i < n; ++i) {cin >> val;ListNode *node = new ListNode(val);node->next = head;head = node;}return head; }//輸入1 2 3 4,輸出4 3 2 13、打印鏈表內容
void PrintList(ListNode *head) {if(head == NULL) {cout << "NULL" << endl;return ;}ListNode *p = head;while(p != NULL) {cout << p->val << " ";p = p->next;}cout << endl; }4、反轉單鏈表
ListNode *ReverseList(ListNode *head) {ListNode *reversedHead = NULL;ListNode *cur = head;ListNode *pre = NULL;while(cur != NULL) {ListNode *next = cur->next;if(next == NULL)reversedHead = cur;cur->next = pre;pre = cur;cur = next;}return reversedHead; }5、求單鏈表的長度
int GetListLength(ListNode *head) {int length = 0;ListNode *p = head;while(p != NULL) {length++;p = p->next;}return length; }6、合并兩個有序鏈表
//遞歸式合并 ListNode *Merge(ListNode *head1, ListNode *head2) {if(head1 == NULL)return head2;if(head2 == NULL)return head1;ListNode *mergeHead = NULL;if(head1->val < head2->val) {mergeHead = head1;mergeHead->next = Merge(head1->next, head2);}else {mergeHead = head2;mergeHead->next = Merge(head1, head2->next);}return mergeHead; }// 非遞歸式合并 ListNode* Merge(ListNode *head1, ListNode *head2) {if(head1 == NULL)return head2;if(head2 == NULL)return head1;ListNode *head = NULL;if(head1->val <= head2->val) {head = head1;head1 = head1->next;}else {head = head2;head2 = head2->next;}ListNode *p = head;while(head1 != NULL && head2 != NULL) {if(head1->val <= head2->val) {p->next = head1;head1 = head1->next;}else {p->next = head2;head2 = head2->next;}p = p->next;}if(head1 != NULL)p->next = head1;if(head2 != NULL)p->next = head2;return head; }7、求鏈表的中間節點,若長度為偶數,則返回前面的節點
ListNode* GetMidNode(ListNode *head) {if(head == NULL || head->next == NULL) // 0個或1個節點,直接返回return head;ListNode *fast = head->next;ListNode *slow = head; // fast走2步,slow走1步while(fast != NULL) {if(fast->next != NULL)fast = fast->next->next;else break;slow = slow->next;}return slow; }8、求鏈表的倒數第k個節點
ListNode *FindKthToTail(ListNode *head, int k) {if(head == NULL || k <= 0)return NULL;ListNode *ahead = head;ListNode *behind = NULL;for(int i = 0; i < k - 1; ++i) { //先向前走 k-1 步,兩個指針的距離保持在k-1if(ahead->next != NULL)ahead = ahead->next;elsereturn NULL;}behind = head;while(ahead->next != NULL) {ahead = ahead->next;behind = behind->next;}return behind; }9、判斷鏈表中是否存在環
// 若返回節點不是NULL則存在環 // 一快一慢兩個指針,快的一次走2步,慢的一次走一步,若存在環,快的肯定能追上慢的 ListNode *MeetingNode(ListNode *head) {if(head == NULL || head->next == NULL)return NULL; // 鏈表為空或者只有1個節點,則不存在環ListNode *slow = head;ListNode *fast = slow->next;while(fast != NULL && slow != NULL) {if(fast == slow)return fast;slow = slow->next;fast = fast->next;if(fast->next != NULL)fast = fast->next;}return NULL; }10、求鏈表中環的入口節點
// 判斷出有環后,求出環中的節點數目,最后求入口節點 ListNode *EntryNodeOfLoop(ListNode *head) {ListNode *meetingNode = MeetingNode(head);if(meetingNode == NULL)return NULL;// 得到環中的節點數目int nodesInLoop = 1;ListNode *node1 = meetingNode;while(node1->next != meetingNode) {++nodesInLoop;node1 = node1->next;}// 先移動node1,次數為環中的節點數目node1 = head;for(int i = 0; i < nodesInLoop; ++i)node1 = node1->next;// 再同時移動node1和node2ListNode *node2 = head;while(node1 != node2) {node1 = node1->next;node2 = node2->next;}return node1; }11、判斷兩個鏈表是否相交(是否是Y字型)
// 判斷兩個鏈表的最后一個節點是否相等 ListNode *InterSect(ListNode *head1, ListNode *head2) {if(head1 == NULL || head2 == NULL)return NULL;ListNode *p = head1;while(p->next != NULL) {p = p->next;}ListNode *q = head2;while(q->next != NULL) {q = q->next;}if(p->val == q->val) return p;return NULL; }?
12、兩個鏈表的第一個公共節點
ListNode *FindFirstCommonNode(ListNode *head1, ListNode *head2) {int length1 = GetListLength(head1);int length2 = GetListLength(head2);int lengthDiff = length1 - length2;ListNode *longList = head1;ListNode *shortList = head2;if(length2 > length1) {longList = head2;shortList = head1;lengthDiff = length2 - length1;}ListNode *FirstCommonNode = NULL;// 先在長鏈表上走幾步,再同時在兩個鏈表上遍歷for(int i = 0; i < lengthDiff; ++i)longList = longList->next;while((longList != NULL) && (shortList != NULL)) {if(longList->val == shortList->val) {FirstCommonNode = longList;break;}longList = longList->next;shortList = shortList->next;}return FirstCommonNode; }13、單鏈表快速排序(交換節點時只需交換節點的值即可)
// 求單鏈表的劃分位置,該位置將鏈表劃分為左右兩個子鏈表 ListNode *Partition(ListNode *head, ListNode *tail) {if(head == tail || head == NULL || head->next == NULL)return head;int key = head->val;ListNode *p = head;ListNode *q = head->next;while(q != tail) {if(q->val < key) {p = p->next;swap(p->val, q->val);}q = q->next;}swap(p->val, head->val);return p; }void QuickSort(ListNode *head, ListNode *tail) {if(head == NULL || head == tail || head->next == NULL)return ;ListNode *partitionPos = Partition(head, tail);QuickSort(head, partitionPos);QuickSort(partitionPos->next, tail); }調用形式為QuickSort(head, NULL)14、單鏈表歸并排序
// 合并兩個有序鏈表 ListNode* Merge(ListNode *head1, ListNode *head2) {if(head1 == NULL)return head2;if(head2 == NULL)return head1;ListNode *head = NULL;if(head1->val <= head2->val) {head = head1;head1 = head1->next;}else {head = head2;head2 = head2->next;}ListNode *p = head;while(head1 != NULL && head2 != NULL) {if(head1->val <= head2->val) {p->next = head1;head1 = head1->next;}else {p->next = head2;head2 = head2->next;}p = p->next;}if(head1 != NULL)p->next = head1;if(head2 != NULL)p->next = head2;return head; }//求單鏈表的中間節點 ListNode* GetMidNode(ListNode *head) {if(head == NULL || head->next == NULL) // 0個或1個節點,直接返回return head;ListNode *fast = head->next;ListNode *slow = head; // fast走2步,slow走1步while(fast != NULL) {if(fast->next != NULL)fast = fast->next->next;else break;slow = slow->next;}return slow; }// 單鏈表歸并排序 ListNode *MergeSort(ListNode *head) {if(head == NULL || head->next == NULL)return head; // 0個或1個節點,直接返回ListNode *head1 = head;ListNode *midNode = GetMidNode(head);ListNode *head2 = midNode->next;midNode->next = NULL;head1 = MergeSort(head1);head2 = MergeSort(head2);// 各自排序后再歸并返回return Merge(head1, head2); }// 調用形式為MergeSort(head)?
總結
- 上一篇: 浮点数大数相加求和
- 下一篇: 你的消息队列如何保证消息不丢失,且只被消