链表总结
链表总结
- 链表是通过指针串联在一起的线性结构,每个节点分为数据域 及 指针域 :
链表可分为 单链表,双链表,循环链表。
单链表
1 链表的定义
- 容易忘记的点,故记录
//single lingked list
struct ListNode {
int val;//storage element
ListNode *next;//pointer to next element
ListNode() : val(0), next(nullptr) {}//constructor1
ListNode (int x) : val(x), next(nullptr) {} //constructor2
ListNode (int x, ListNode *ptr) : val(x), next(ptr) {} //constructor3
};
ListNode* L1 = new ListNode(5); // init 1
/*or*/
ListNode* L2 = new ListNode();
L2->val = 5;
2 链表的操作
- 若引入头节点,链表的操作将简单许多:
class Solution {
public:
ListNode* CreatDummyHead(ListNode* head) {
ListNode* dummyhead = new ListNode(0);//virtual head node
dummhead->next = head;
return dummyhead;
}
}
3 链表相关算法题的经典解决方法
3.1 双指针法
双指针法是一个很经典的方法,在链表、数组等地方都有很经典的应用,笔者更喜欢通过题目探究应用。题目为代码随想录中所挑出的经典算法。
- LettCode:反转链表
题目描述:
设置两个节点P1,P2
反转操作为:
1、储存P2.next到temp
2、P2.next = P1
3、P1 = P2
4、P2 = temp - LettCode:删除倒数第n个节点
题目描述:
- LettCode:两两交换链表中的节点
设置两个指针P1、P2,P1指向head,P2指向node1(如果指向node1和node2的话,前面节点无法表示),进行节点交换,交换后一次移动两个,需要注意的是终止条件是:P1后存在两个节点则交换,否则不进行交换。代码如下:
class Solution {
public:
ListNode* swapPairs(ListNode* head) {
ListNode* dummy_head = new ListNode(0);
dummy_head->next = head;
ListNode* p1 = dummy_head;
while(p1->next && p1->next->next)
{
ListNode* p2 = p1->next;
ListNode* p3 = p2->next;
ListNode* tmp1 = p3->next;
p1->next = p3;
p3->next = p2;
p2->next = tmp1;
p1 = p1->next->next;
}
return dummy_head->next;
}
}
3.2 递归法
递归法看似简单,但是在写算法的时候总会绕进去(事实上脑子并没有几个栈,不能跳进去,但是忍不住......),没有彻底清楚的感觉,只能一点点的总结,一点点的理解。
递归的三要素:本级递归的任务,终止条件,返回值
- LettCode:反转链表
这个题的第二种办法就是递归法,我们需要梳理我们这道题所对应的三要素是什么。
递归的其中之一的要素,返回条件是:反转后形成新链表的头节点(返回值)。
同时怎么结束呢?当链表中没有可交换的节点则结束,就是只剩一个节点,或者没有节点,终止条件就是:只剩一个节点,或者没有节点(终止条件)
我们本级递归所要做的事情就是:反转(本级递归的任务)
reverse函数里就光反转节点,在参数传递中已经将指针进行了移动。
class Solution {
public:
ListNode* reverseList(ListNode* head) {
return reverse(NULL,head);
}
ListNode* reverse(ListNode* p1 ,ListNode* p2)
{
if(!p2) {return p1;}
ListNode* tmp = p2->next;
p2->next = p1;
//p1 = p2;
//p2 = tmp;
return reverse(p2,tmp);
}
};
- LettCode:两两交换链表中的节点
递归的图参考的就是lyl's blog的博客,其实两两交换节点,可以抽象成,本级递归的任务就是交换noden 和noden+1 即可,然后行成新的完成链表返回。
对应三要素:
终止条件:没有可交换节点
本级递归的任务:交换节点
返回值:新的完成链表的头节点
class Solution {
public:
ListNode* swapPairs(ListNode* head) {
ListNode* n = head;
if(n == nullptr || n->next == nullptr)
{
return n;
}
ListNode* nnext = n->next;
n->next = swapPairs(nnext->next);
nnext->next = n;
return nnext;
}
};
3.3 环形列表的知识点
- 判断链表是否有环
- 怎么找到入口?
文章引用自代码随想录:代码随想录,还有lyl's blog