单链表操作
判断链表是否有环
- 思路:通过两个指针,都从头部开始遍历,第一个指针顺着链表进行遍历,另一个指针一次跳过一个进行遍历,若两个指针相交,则表示指针有环
两个链表是否有交点
- 思路:两个链表的尾节点是否相同
有交点,求第一个交点
- 思路:求出S1的长度length1,S2的长度length2,较大先走abs(length1-length2),然后一起走,相等即为交点。
求入环点
- 思路:从链表头和碰撞节点到入口距离相等:
证明如下:
假设满走的长度为s, 快指针走的长度为2s,环的长度为r,链表长度为L,入口到相遇点为x,环入口为a,则:
2s = s + nr -> s = nr
a + x = s = nr (s为相遇点的距离)
a + x = (n-1)r + r
a + x = (n-1)r + L-a
a = (n-1)r + L - a - x
其中:(n-1)r是周期性的,而L- a - x为相遇点到环的入口点的距离。故而由:a = L - a - x,即:链表头和碰撞节点到入口距离相等。
求环的长度
- 设pos1为碰撞节点,pos2为从碰撞节点开始遍历环的游标,当到达pos1时,则为环的长度。
带环链表的长度
- 设碰撞节点为pos1,头结点为pos2,则链表的长度为:头结点到入口的长度+环的长度
链表原地逆序
node_t * reverse_list(node_t *head)
{
node_t *pre = NULL, *pos, *next = NULL, *ret = NULL;
if (head == NULL)
return NULL;
pos = head;
while(pos) {
next = pos->next;
if (next == NULL)
ret = pos;
pos->next = pre;
pre = pos;
pos = next;
}
return ret;
}
去掉冗余项
问题描述
- 一个没有排序的链表,比如list={a,l,x,b,e,f,f,e,a,g,h,b,m},请去掉重复项,并保留原顺序,以上链表去掉重复项后为newlist={a,l,x,b,e,f,g,h,m},请写出一个高效算法(时间比空间更重要)。
分析
- 利用hash_map, key为链表中已经遍历的节点的内容,开始时为空。从链表头开始遍历:若节点内容以存在在hash表中,则将该节点从链表上摘除;若不存在在hash表上,则将节点内容添加到hash表中,继续向后遍历
代码实现
#include <map>
#include <string>
struct list{
char value;
struct list *next;
};
void delete_duplicate(struct list *head)
{
struct list * list = head, *tmp, *prev = head;
map<char, char> value_map;
while(list != NULL){
if (value_map.find(list->value) != value_map.end()) {
//冗余
prev->next = list->next;
list = list->next;
} else {
value_map[list->value] = list->value;
prev = list;
list = list->next;
}
}
}