顺序表.链表与链表oj

顺序表.链表与链表oj

  1. 顺序表

    顺序表是用一段物理地址连续的存储单元依次存储数据元素的线性结构,一般情况下采用数组存储。在数组上完成数据的增删查改。
    顺序表有静态和动态两种 静态顺序表只适用于确定知道需要存多少数据的场景。静态顺序表的定长数组导致N定大了,空间开多了浪费,开少了不够用。所以现实中基本都是使用动态顺序表,根据需要动态的分配空间大小,所以下面我们实现动态顺序表。
    顺序表就和数组差不多
    顺序表实现

  2. 链表
    链表是一种物理存储结构上非连续、非顺序的存储结构,数据元素的逻辑顺序是通过链表中的指针链接次序实现的 。
    链表也有很多种
    带哨兵位与不带哨兵位 双向与单向 循环与不循环
    可以有八种组合 可以根据自己的需求选择
    其中带哨兵位的双向循环链表是最全面的 可以相对轻松实现很多功能
    单链表实现
    带头双向循环链表实现

  3. 链表oj题1
    带环链表
    顺序表.链表与链表oj_第1张图片
    这里需要使用快慢指针
    1.判断是否有环
    顺序表.链表与链表oj_第2张图片
    如果存在环就像这样 一个fast一个slow指针同时指向头节点phead
    让fsat一次走两步 slow一次走一步 那么当slow走到入环点时
    fast一定已经入环 不管在环内是否已经绕圈
    顺序表.链表与链表oj_第3张图片
    只要据续走 那么fast 和 slow一定要相遇
    即快慢指针在链表结束前相遇就证明链表有环(有环链表不会结束)
    顺序表.链表与链表oj_第4张图片

2.如果有环找到入环点
这里需要用到数学证明
顺序表.链表与链表oj_第5张图片
不妨设链表头到入环点为L 环的周长为n 两快慢节点第一次相遇点到入环点为x
这时候把fast移回头节点 但现在fast和slow都每次走一步 当指针再次相遇就是入环点
解析:顺序表.链表与链表oj_第6张图片
顺序表.链表与链表oj_第7张图片

结合图片推敲即可 实现代码如下

struct ListNode *detectCycle(struct ListNode *head) {
    struct ListNode *slow=head,*fast=head;

    while(fast && fast->next)
    {
        fast=fast->next->next;
        slow=slow->next;

        if(fast==slow)
        {
            fast=head;
            while(fast!=slow)
            {
                fast=fast->next;
                slow=slow->next;
            }
            return fast;
        }
    }
    return NULL;
}

此题还有另外一个方法
在第一次相遇后就把环断开 如图
顺序表.链表与链表oj_第8张图片
就变成了两个链表找交点的问题了(leetcode有这个oj题)
找交点 leetcode oj
代码实现

struct ListNode *getIntersectionNode(struct ListNode *headA, struct ListNode *headB) {
    struct ListNode *heada=headA,*headb=headB;
    int a=1,b=1;
    while(heada->next)
    {
        a++;
        heada=heada->next;
    }
    while(headb->next)
    {
        b++;
        headb=headb->next;
    }

    if(heada!=headb)
    return NULL;

    int value=abs(a-b);

    struct ListNode* longlist=headA,*shortlist=headB;
    if(a<b)
    {
        longlist=headB;
        shortlist=headA;
    }
    while(value--)
    longlist=longlist->next;
    while(longlist!=shortlist)
    {
        longlist=longlist->next;
        shortlist=shortlist->next;
    }
    return longlist;
}

struct ListNode *detectCycle(struct ListNode *head) {
    struct ListNode *slow=head,*fast=head;

    while(fast && fast->next)
    {
        fast=fast->next->next;
        slow=slow->next;

        if(fast==slow)
        {
            slow=fast->next;
            fast->next=NULL;

            return getIntersectionNode(slow,head);
        }
    }
    return NULL;
}
  1. 链表oj题2
    链表的深度拷贝
    顺序表.链表与链表oj_第9张图片
    顺序表.链表与链表oj_第10张图片
    由于每个节点都有两个指针 所有这些数据有两种循序
    1 暴力求解
    可以先把next的指向循序复制一遍
    由于链表空间不连续 不能使用相对距离来定位下一个节点的位置
    所以需要不断遍历链表确定rondom指向的地址
    这种方法当然可以实现 但时间复杂的为O(n^2)
    也可以使用数组先把数据存放起来再复制 都是可以的 只是都效率不高
    另一种方法
    复制每一个节点 分别接在每个节点后面 如图
    顺序表.链表与链表oj_第11张图片
    然后再复制rondom指针 如
    7的原节点rondom指向NULL 使7的复制节点也指向NULL
    13的原节点rondom指向7原节点 使13的复制节点也指向7的复制节点
    当全部都复制完再把原节点去掉 时间复杂度为O(n)
    实现如下
struct Node* copyRandomList(struct Node* head) {
    if(head==NULL)
    return NULL;
	struct Node *cur=head;
    while(cur)
    {
        struct Node *copynode=(struct Node*)malloc(sizeof(struct Node));

        copynode->next=cur->next;
        cur->next=copynode;
        copynode->val=cur->val;

        cur=cur->next->next;
    }
    cur=head;
    while(cur)
    {
        if(cur->random)
        {
            cur->next->random=cur->random->next;
        }
        else
        {
            cur->next->random=cur->random;
        }
        cur=cur->next->next;
    }
    cur=head->next;
    while(cur->next)
    {
        cur->next=cur->next->next;
        cur=cur->next;
    }
    return head->next;
}

你可能感兴趣的:(链表,数据结构)