数据结构3:链表的运用和循环链表
数据结构3:链表的运用
写在前面:
链表是数据结构中很重要的一个,为此,我会单开一个章节来记录链表的使用,请不要好高骛远。
例题一:倒数定位
假设该链表只给出了头指针S。在不改变链表的前提下,请设计一个尽可能高效
的算法,查找链表中倒数第k个位置上的结点(k为正整数)。若查找成功,算法输出
该节点的data域的值,并返回1;否则,只返回0。
值得注意的是,如果我们一直遍历到链表的末尾,再掉头,无疑会导致极高的时间复杂度。所以
,我们会使用快慢指针的速度差来表示k。比如,k == 3,那么,我们设定两个指针Fast和slow,让Fast先走三步,slow再开始走,那么,当Fast走到最后(Fast指针指向空指针)时,slow的位置就是Fast往前三步的节点。
所以,具体的代码实现是:
1 |
|
例题二:共同后缀
假定采用带头节点的单链表保存单词,当两个单问有相同的后缀时,则可共享相同的后缀存储空间,例如,“loading”和“being”的存储映像如下图所示。
设str1和str2分别指向两个单词所在单链表的头节点,请没计一个时间上尽可能高效的算法,找出由Sr1和str2所指向两个链表共同后缀的起
始位置(如图字符i所在结点的位置p)。
这里用哈希表可能更好,但是我还没学到。
所以,每个链表都有一个相同的后缀,后缀的长度是一定的,所以,我们获取两个链表的长度,他们之差就是后缀的长度,再用快慢指针就可以定位到共同后缀的第一个字母了。
例题三:绝对值替换
用单链表保存 n 个整数,现要求设计一个时间复杂度尽可能高效的算法,对于链表中 data 的绝对值相等的节点,仅保留第一次出现的节点而删除其余绝对值相等的结点。
我们可以设置一个长度大于n+1
(n个整数加上一个数据域为空的头节点就是n+1)的数组a,并将其初始化为0。然后,遍历整个链表,设置条件判断(这里说的date都是实际链表中的数据域的绝对值):如果a[date]==0,将其设置为1,如果a[date] == 1,说明该date已经出现过了,就删除该节点,这就实现了ACM中类似的打表操作。遍历到末尾时,执行完毕。
例题四:反转链表
给你一个单链表,要求你反转链表方向。
首先,我们需要三个指针,指针first指向NULL,指针Second指向头节点,指针Three指向头节点之后的一个节点,然后,只要Second的指针域不为空指针,将Second的指针域指向first,然后将first指向second,将second指向three,黑体操作就实现了操作器的移动。直到末尾,我们的反转工作就完成了。
循环链表
循环链表(Circular Linked List)是另一种形式的链式存储结构。其特点是表
中最后一个节点的指针域指向头节点,整个链表形成一个环。
循环链表的判别条件是:P-> != HEAD
但是实际使用中往往不是纯的环,可以是这样的结构: