-
概念
- 链表是一种物理存储结构上非连续、非顺序的存储结构,数据元素的逻辑顺序是通过链表中的指针链 接次序实现的 。
-
两种链表
-
/*不带头不循环单向链表*/ typedef int SLDataType; typedef struct SListNode { SLDataType val; struct SListNode* next; }SListNode;
-
/*带头双向循环链表*/ typedef int DListType; typedef struct ListNode { struct ListNode* prev; struct ListNode* next; DListType val; }ListNode;
-
几个常见的oj题
-
[翻转链表](206. 反转链表 - 力扣(LeetCode))
-
思路1:用三个指针,遍历一遍链表,改变指针的朝向
-
// 指针翻转 class Solution { public: ListNode* reverseList(ListNode* head) { if(head == nullptr) return nullptr; // 用三个指针,翻转指针方向 ListNode* cur, *prev, *next; cur = head, prev = nullptr, next = head->next; while(cur) { cur->next = prev; prev = cur; cur = next; if(next != nullptr) next = next->next; } return prev; } };
-
思路2:使用递归
-
// 递归 class Solution { public: ListNode* reverseList(ListNode* head) { return recur(head, nullptr); } private: ListNode* recur(ListNode* cur, ListNode* prev) { if(cur == nullptr) return prev; ListNode* res = recur(cur->next, cur); cur->next = prev; return res; } };
- 下面是思路2的递归展开图
-
{:height 705, :width 758}
-
[合并两个有序链表](21. 合并两个有序链表 - 力扣(LeetCode))
-
思路:用两个指针指向两个链表的开头,取两个链表val小的尾插到新的链表
-
class Solution { public: ListNode* mergeTwoLists(ListNode* list1, ListNode* list2) { ListNode* l1 = list1, *l2 = list2; // 建一个哨兵位 ListNode* head, *tail; head = tail = new ListNode[1]; tail->next = nullptr; while(l1 != nullptr && l2 != nullptr) { if(l1->val < l2->val) { tail->next = l1; l1 = l1->next; tail = tail->next; } else { tail->next = l2; l2 = l2->next; tail = tail->next; } } // 看看是l1没完还是l2没完 if(l1 != nullptr) tail->next = l1; if(l2 != nullptr) tail->next = l2; ListNode* ret = head->next; delete[](head); // 注意:这里要是delete[] return ret; } };
- 启示:遇到链表尾插的题,加上头结点会轻松许多
-
[环形链表](141. 环形链表 - 力扣(LeetCode))
-
思路:快慢指针:快指针一次走两步,慢指针一次走一步,如果相遇,证明有换
-
class Solution { public: bool hasCycle(ListNode *head) { ListNode* fast, *slow; fast = slow = head; while(fast && fast->next) { slow = slow->next; fast = fast->next->next; if(slow == fast) return true; } return false; } };
- 问题:快指针一次走三步,慢指针一次走一步可以吗?
- 不可以,有一定几率会错过,如下图
- {:height 317, :width 673}
- 当fast一次走4步,下图的情况仍然不会相遇
- {:height 241, :width 468}
-
[环形链表2](142. 环形链表 II - 力扣(LeetCode))
-
思路:一个指针从开始走,一个指针从相遇点开始走,他们相遇的点就是链表的开头
-
class Solution { public: ListNode *detectCycle(ListNode *head) { ListNode* fast = head, *slow = head, *meet; while(fast && fast->next) { slow = slow->next; fast = fast->next->next; if(fast == slow) { meet = fast; // 找到第一次相遇的点 while(meet != head) { meet = meet->next; head = head->next; } return meet; } } return NULL; } };
- 为什么会这样呢?下图给出了解释
- {:height 332, :width 778}
基础数据结构链表以及oj题目
最新推荐文章于 2024-11-05 22:40:01 发布