顺序表和链表总结

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档


一、对比

1.顺序表:

1.开辟方式
通过在堆上开辟空间,为什么要在堆上开辟空间呢?因为,出了函数数据不销毁的有三种:全局变量,静态变量,和在堆上开辟的空间,因为在堆上开辟的空间,如果没有free掉,出了函数的作用域还是会存在,所以只要返回一个头指针就可以管理起来,很方便。
当然也有静态的,就是一开始就把空间给固定死的那种,不过呢,这种很不方便,比如,我们开了1000个数据的空位,但是用户只需要存一个数据,这就会造成空间的浪费当然还有就是空间不够的画就会很难受,因为空间的大小被固定死了。

2.优势:

访问速度快,可以直接通过下标进行数据的访问,尾插效率高。

3.劣势:

因为当空问不够时,我们是按照原空问的两倍进行realloc所以也会造成空间上的一定浪费,而每一次的realloc数据批会新进行拷贝一份,所以效率不高。

在头插或者是某个位置插入,数据都会移动(假设数据长度是n,要插在下标为i的位置移动)n-i次.
在删除中间的某个数据时,数据会移动n-i-1个数据,效率也很低。

 

 


2.单链表:

                          
在物理空间上不一定连续,因为是通过malloc出来的,地址是随机的。
在逻辑上一定是连续的。
优势:
头插,尾插,在pos位置插入数据,头删,效率都很高,内存的管理非常好,需要多少开辟多少不会造成内存的浪费。
劣势:
对于尾删,删除在pos位置的数据的效率很低,因为不仅需要找到他们的对应位置,还需要找到对应位置的前一个,但是对于单链表来说找到对应位置的前一个就需要再遍历一遍,所以效率是比较低的。
                                                  

所以,单链表虽然解决了,空间的浪费,但是还是有着一定的缺陷,所以就出现双向带头链表。
结构如下,虽然看起来比较复杂,但是很好用。

 

可以看见,双向带头链表直接解决了单链表中,尾删,在pos位置删除需要走两遍的问题,因为他们每一个数据都存有上一个数据的地址,这样就不需要走两遍了,而且头删,头插,在pos位置插入的效率同样是很高的。


二、经典例题

88. 合并两个有序数组 - 力扣(Leetcode)icon-default.png?t=M85Bhttps://leetcode.cn/problems/merge-sorted-array/

 

 

 代码如下:

void merge(int* nums1, int nums1Size, int m, int* nums2, int nums2Size, int n)
{
    int p=m+n-1;//nums1的最右边的下标
    int p1=m-1;//nums1中需要比较的数据
    int p2=n-1;//nums2右端下标

    while(p1!=-1&&p2!=-1)
    {
            if(nums1[p1]>nums2[p2])
            {
                nums1[p]=nums1[p1];
                p--;
                p1--;
            }
            else
            {
                nums1[p]=nums2[p2];
                p--;
                p2--;
            }
    }

    while(p2!=-1)
    {
        nums1[p]=nums2[p2];
        p--;
        p2--;
    }

   
}


876. 链表的中间结点 - 力扣(Leetcode)icon-default.png?t=M85Bhttps://leetcode.cn/problems/middle-of-the-linked-list/description/

 

 

代码如下:

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */

struct ListNode* middleNode(struct ListNode* head)
{
    //快指针一次走两步,慢指针一次走一步
    struct ListNode* fast=head;
    struct ListNode* slow=head;

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

    return slow;

}


160. 相交链表 - 力扣(Leetcode)icon-default.png?t=M85Bhttps://leetcode.cn/problems/intersection-of-two-linked-lists/description/

 

 代码如下:

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */
struct ListNode *getIntersectionNode(struct ListNode *headA, struct ListNode *headB)
{
    struct ListNode *p1=headA;
    struct ListNode *p2=headB;
    
    while(p1!=p2)
    {
        p1=(p1==NULL? headB:p1->next);
        p2=(p2==NULL?  headA:p2->next);

    }

    return p1;
}


141. 环形链表 - 力扣(Leetcode)icon-default.png?t=M85Bhttps://leetcode.cn/problems/linked-list-cycle/description/

 

 理解如下:

 代码如下:

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */
bool hasCycle(struct ListNode *head)
{
    
    struct ListNode *slow=head;
    struct ListNode *fast=head;

    while(fast&&fast->next)
    {
        fast=fast->next->next;
        slow=slow->next;
        
        if(fast==slow)
        {
            return true;
        }
    }

    return false;
}

142. 环形链表 II - 力扣(Leetcode)icon-default.png?t=M85Bhttps://leetcode.cn/problems/linked-list-cycle-ii/description/

 

 代码如下:

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */
struct ListNode *detectCycle(struct ListNode *head) 
{
    struct ListNode *slow=head;
    struct ListNode *fast=head;

    while(fast&&fast->next)
    {
        fast=fast->next->next;
        slow=slow->next;
        
        if(fast==slow)
        {
           struct ListNode *meet=fast;
            struct ListNode *cur=head;
            while(meet!=cur)
            {
             
                cur=cur->next;
                meet=meet->next;
            }

            return cur;
        }
    }

    return NULL;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值