链表定义:
是一种递归的数据结构,它或者为空,或者是指向一个node的引用,该结点还有一个元素和指向另一条链表的引用。(结点+指向下一个node的指针)
链表特点:
- 最后一个节点的next指向null。
- 与数组不同,不需要new出一块空间,所以不用考虑空间不足和浪费的问题。
- 需要多少,就会生成多少挂接起来。
因此,链表具有动态的能力,不需要处理固定容量的问题
但是,由于动态的能力,确实了高效的随机访问(random access )的能力。也就是不能像数组一样通过index 来访问对应的元素。链表靠next链接,每个节点的存储地址都不同,我们只能用next来找到自己要找的元素。所以,增删改查操作的复杂度都是O(n),数组是O(1)
插入node:
1 | insertNode.next = prevNode.next |
删除node:
1 | prevNode.next = delNode.next |
链表相关问题:
反转链表:
输入一个链表,反转链表后,输出链表的表头。
思路:现在的node去指向前一个Node,后面的Node指向前面的Node,知道最后一个Node:
1 | # -*- coding:utf-8 -*- |
链表中环的入口结点:
在一个链表中,若有环,输出环的入口结点,否则输出null。
思路:一个fast指针一次移动两个结点,一个slow指针一次移动一个结点。因为有环所以两个必定相遇。相遇之后,fast从头结点出发变为一次一步,slow和fast会在环入口相遇。
1 | # -*- coding:utf-8 -*- |
删除链表中的重复结点:
在一个排序的链表中,存在重复的结点,请删除该链表中重复的结点,重复的结点不保留,返回链表头指针。 例如,链表1->2->3->3->4->4->5 处理后为 1->2->5
思路: 有重复就跳过,对后面的node进行递归去重。
1 | # -*- coding:utf-8 -*- |
链表中倒数第K个结点:
输入一个链表,输出该链表中倒数第k个结点。
思路:两个指针,P1移动K个结点,所以还剩下N-K个结点,这时候P2从头结点出发,P1到达最后一个结点时候,P2正好也走了N-K个结点,也就是倒数第K个。
1 | # -*- coding:utf-8 -*- |
合并两个排序的链表:
输入两个单调递增的链表,输出两个链表合成后的链表,当然我们需要合成后的链表满足单调不减规则。
思路:递归
1 | # -*- coding:utf-8 -*- |
两个链表的第一个公共结点:
输入两个链表,找出它们的第一个公共结点。
思路:两个链表分别放入栈,每次同时弹出一个,最后一个相同的结点就是第一个公共结点。
1 | # -*- coding:utf-8 -*- |
二叉搜索树与双向链表:
输入一棵二叉搜索树,将该二叉搜索树转换成一个排序的双向链表。要求不能创建任何新的结点,只能调整树中结点指针的指向。
思路:二叉搜索树的特点:左结点<根结点<右结点。所以用中序遍历,就可排序。
1 | # -*- coding:utf-8 -*- |