1.顺序表
顺序表是在计算机内存中以数组的形式保存的线性表,是指用一组地址连续的存储单元依次存储数据元素的线性结构。线性表采用顺序存储的方式存储就称之为顺序表。顺序表是将表中的结点依次存放在计算机内存中一组地址连续的存储单元中。
此种数据结构不适合大量的插入和删除,此类在数据内部进行操作都至少移动一半的数据位置,适合存储被用来进行访问的操作。
2.链表
利用指针实现线性表的方式,此类表示法通常称为链表。链表是动态的,即可根据需要进行空间的分配。
2.1单链表
每个结点只有一个指向下一个的结点的指针,称为单链表。
template <typename E>
typed struct link
{
E data;
node* next;
}node*;
2.2双链表
顾名思义,双链表是存在head 和tail指针,且每个结点相对单链表多了一个向前指向的指针,pre。
template <typename E>
typed struct link
{
E data;
node* next;
node* pre;
}node*;
2.3关于链表的一些问题
(1)链表中的环
链表中存在环是尾指针指向了链中的某一个结点,才使得链结尾有一个环。
1)如何判断链中有环
思想是设置两个指针,这俩指针“行驶速度不同”,如果这两指针不会相遇即不存在环,反之,存在环的结构。
2)如何判断链表中环的长度
思想是在环上相遇后,记录第一次相遇点为Pos,之后指针slow继续每次走1步,fast每次走2步。在下次相遇的时候fast比slow正好又多 走了一圈,也就是多走的距离等于环长。
设从第一次相遇到第二次相遇,设slow走了len步,则fast走了2*len步,相遇时多走了一圈:
环长=2*len-len。
3)如何判断环的入口结点的位置
思想是从第一次相遇的点,此点到入口的距离与头结点到入口的距离相同。
简单的计算过程:
假设链的前部分长度是L,环的长度是R,两指针第一次相遇点到入口位置的距离是k,两指针的速度比是1:2,fast已经在环中走过n圈 了,所以在第一次相遇时此时两指针走过的长度,S_fast=L+n*R+K;S_slow=L+K;而两者的关系是1:2,所以, L+n*R+K=2*L+2*K;
即L=n*R-K,--->L=(n-1)*R+R-K;
所以在第一次的相遇点设置一指针继续往前走,同时,头指针也开始行走,两指针必然在入口点相遇。
4 )如何知道两个单链表(无环)是否相交
法一:将链表A的尾节点的next指针指向链表B的头结点,从而构造了一个新链表。问题转化为求这个新链表是否有环的问题。
时间复杂度为环是否存在的时间复杂度,即O(length(A)+length(B)),使用了两个额外指针
法二:两个链表相交,则从相交的节点起,其后的所有的节点都是都是两个链表共有的。因此,如果它们相交,则最后一个节点一定是共有的。因此, 判断两链表相交的方法是:遍历第一个链表,记住最后一个节点。然后遍历第二个链表,到最后一个节点时和第一个链表的最后一个节点做比较,如果 相同,则相交。
时间复杂度:O(length(A)+length(B)),但是只用了一个额外指针存储最后一个节点
5)如果两个单链表(无环)相交,如何知道它们相交的第一个节点是什么
将链表A的尾节点的next指针指向链表B的头结点,从而构造了一个环。问题转化为求这个环的入口问题。
时间复杂度:求环入口的时间复杂度
6)如何知道两个单链表(有环)是否相交
如果仅有一个有环,则A、B不可能相交
如果两个都有环,则求出A的环入口,判断其是否在B链表上,如果在,则说明A、B相交。
时间复杂度:“环入口问题的时间复杂度”+O(length(B))
7)如果两个单链表(有环)相交,如何知道它们相交的第一个节点是什么
分别计算出两个链表A、B的长度LA和LB(环的长度和环到入口点长度之和就是链表长度),参照问题3。
如果LA>LB,则链表A指针先走LA-LB,链表B指针再开始走,则两个指针相遇的位置就是相交的第一个节点。
如果LB>LA,则链表B指针先走LB-LA,链表A指针再开始走,则两个指针相遇的位置就是相交的第一个节点。
时间复杂度:O(max(LA,LB))