第一篇终结Linked List(一)、终结Linked List(二)主要讲了单链表的基础知识,接下来的第二篇主要讲一些比较经典的问题。
一、Count()
给一个单链表和一个整数,返回这个整数在链表中出现了多少次。
1 | /* |
也可以用for
循环实现。
二、GetNth()
给一个单链表和一个index,返回index位置上的数值,类似array[index]
操作。
1 | /* |
三、DeleteList()
给一个单链表,删除所有节点,使head
为NULL
。
删除链表{1,2,3}
的示意图:
1
2
3
4
5
6
7
8
9
10
11void DeleteList(struct node** headRef)
{
struct node* cur = *headRef; //deref headRef to get the real head
while (*headRef)
{
cur = *headRef;
*headRef = cur->next;
free(cur);
}
}
四、Pop()
给一个链表,删掉头节点,返回头节点的数据。
内存示意图:
1 | /* |
五、InsertNth()
可以在[0,length]
的任意位置插入指定元素。
1 | /* |
这段代码坑有点多,可以通过画图或者单步跟踪的方法调试。
InsertNthTest()
可以用来测试:
1 | void InsertNthTest() |
六、SortedInsert()
给定一个有序链表和一个节点,将该节点插入到合适的位置。 共有三种方法:
1、Uses special case code for the head end 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20void SortedInsert(struct node** headRef,struct node* newNode)
{
//Special case for the head end
if (newNode->data <= (*headRef)->data || *headRef == NULL)
{
newNode->next = *headRef;
*headRef = newNode;
}
else
{
//Locate the node before the point of insertion
struct node* cur = *headRef;
while (cur->next && cur->next->data < newNode->data)
{
cur = cur->next;
}
newNode->next = cur->next;
cur->next = newNode;
}
}dummy node
这种方法一般不需要处理特殊情况。
1 | void SortedInsert2(struct node** headRef,struct node* newNode) { |
3、Local references strategy for the head end
1 | void SortedInsert3(struct node** headRef,struct node* newNode) |
链表反转
链表反转的题目都是套路, 如果要反转\([l,r)\)内的部分, 需要记录l的前一个结点.
让cur = l, prev = r
, 循环次数等于\([l,r)\)内的结点数, 每次循环都是标准操作:
1
2
3
4tmp = cur.next
cur.next = prev
prev = cur
cur = tmp
最终cur
指向r,
prev
指向反转后的第一个结点即原链表的r - 1.
头结点主要看你是反转整个链表还是一部分,反转整个链表就没必要了,因为l直接指向头结点
92题可以直接按照上述方法做,但是开始要把r指向正确的位置,相当于多走了一遍,因此开始把prev设置为None,反转结束先通过l前一个结点修正l的指针指向cur,再让l前一个结点指向prev
25题因为要分组反转,所以需要判断剩余的结点够不够k个,因此r必然需要向后走一遍去判断,因此[l,r)肯定要走2遍。