链表的结构,如何定义链表?单链表?多链表?
struct ListNode {
int val; //值
ListNode* next;
//还可以定义一些TreeNode的构造函数。就形成了一个基本的链表结构。例:
ListNode(){val(null); next(NULL);}
}
单链表如何遍历?双向链表如何遍历?
对单链表来说,只能从头结点向后遍历,即head=head.next; 双向链表有head和tail两个“哨兵”结点,可以沿两个方向遍历。
链表中的结点的增/删/改,甚至反转等操作,要用到pre, cur, nxt三个指针。
对链表进行增删时可以通过直接对head结点进行操作,这种方式则需要单独处理头结点。另一种比较好的方式是增设一个虚拟头结点,好处是可以不用单独处理头结点,因此比较推荐。以一个问题为例。
问题: 删除链表中所有结点val等于指定值的结点。
输入:ListNode *head; 案例:[1, 4, 5, 1, 3, 1, 2, 6],删除target=1。输出:ListNode *head=[4, 5, 3, 2, 6];
思路: 可以看到头结点也是需要删除的结点,通过增设虚拟头结点的方法处理。
ListNode * reverseList(ListNode* head, int target){
ListNode* dummynode=new ListNode();
dummynode.next=head;
ListNode* p=dummynode;
while(p.next!=NULL){
if(p.next.val==target){
ListNode* tmp=p.next;
p.next=p.next.next;
delete tmp;}
}else{p=p.next;}
return dummynode.next; //这里要返回虚拟头结点的下一个结点。
}
参考:
https://mp.weixin.qq.com/s/Cf95Lc6brKL4g2j8YyF3Mg
问题: 给定一个链表head,按照如下方式变换链表。
输入: 1, 2, 3, 4, 5
输出: 1, 5, 2, 4, 3
分析: 从输入与输出结果看,需要将链表后半部分结点,反向并间隔的插入到前半部分结点之中。从<问题: 反向输出链表结点>出发,反向输出链表结点需要使用栈(stack)。将后半部分结点压入栈中。逐个弹出并插入前半部分中。