单链表的常用操作实现:删除、增加、反转、环形…
下面是对单链表的一些总结:
定义情况如下:
1 | #define TRUE 1 |
1. 针对一个单链表的常用操作
##(1)给点一个值value,删除链表中等于此值的节点
先判断头节点的值是否为value,是的话,改变头指针,指向下一个节点;
否则,遍历链表,知道找到一个节点,他的next的值为value,
将此节点指向下下个节点,最后删除中间的节点。
程序如下:
1 | void removeNode ( Node ** head, int value){ |
##(2)在链表尾部新增一个节点,其值为value:
先分配空间,初始化新的节点;如果链表为空,则头部指向新节点;
否则,在尾部直接添加新节点即可;
程序如下:
1 | void addNodeToTail ( Node ** head, int value){ |
##(3)打印一个单链表,但是输出的顺序反向:
可以利用递归,知道最后一个节点(next=NULL)时才打印;
然后从栈中返回前面调用的函数,实现了反向打印。
程序如下:
1 | void printListReversely ( Node * head ){ |
##(4)翻转一个单链表,即把原来的链表反向:
只需改变链表中每一个箭头的方向即可;
需要3个变量,一个保存现在的节点,一个保存前一个节点,一个保存下一个节点。
程序如下:
1 | Node * reverseLinkList ( Node * pHead ){ |
##(5) 判断一个链表是否有环
如果链表有环,必定出现在尾部;就像去操场前,需要先走一段路,再进入圆形的跑道;
可以设定两个指针,开始都指向head,然后一个指针每次走2步,另外一个每次一步;
如果有环,经过圆形环后,快指针必定会追上慢指针;
如果碰到指针指向NULL了,则没有环。
程序如下:
1 | bool isLoopInList (Node * head){ |
##(6)如果一个链表有环,请找出进入环的第一个节点
用步骤(5)的方法判断有环时,快慢指针相遇,然后将慢指针重新置为head,
快指针停留在相遇的节点;
这时候,都同时走,每次一步,再次相遇时,必定在进环的第一个节点。
(可以按照圆环的路径证明)
程序如下:
1 | Node * fistNodeOfLoop(Node * head){ |
##(7) 打印链表的倒数第K个节点
设定2个指针,先让一个走k-1步,然后一起走,每次一步;
当前面的指针走到尾时,后的指针刚好走到倒数第K个节点。
程序如下:
1 | Node * FindLastKNode ( Node * head, unsigned int k ){ |
#2. 以上都是针对一个单链表的操作,下面讨论两个单链表,
现在讨论两个单链表的相交情况
##(1)判断给定的2个单链表是否相交
由节点指向的单一性,相交后不会再分开;即相交后的形状如Y,不是X;
可以分别遍历2个链表,只需判断最后一个节点是否一致,一致则相交,不一致则不相交;
时间复杂度为 O(m+n)
1 | bool HasCommonNodeOf2Lists ( Node * p1,Node * p2 ){ |
##(2) 如果两个链表相交,找出第一个相交的节点
两个链表可能有长有短,可以分别遍历2个链表,计算出长度差diff;
然后,在长链表上先走diff步,再同时走,直到节点相等时停止,
这个节点即为第一个相交的节点。
程序如下:
1 | Node * firstCommonNodeOf2Lists ( Node * head1,Node * head2 ){ |