数据结构(初阶1)---顺序表及其练习(双指针)

一.顺序表

1.顺序表的基本性质

(1).顺序表是一串物理地址连续的线性结构,与数组极其相似
(2).顺序表的逻辑也连续
ps:
物理连续:即地址的连续,数据的连续储存
逻辑连续:比如arr[1],arr[2],arr[3]他们在逻辑上是连续的,(是程序员大 脑里的连续的)

2.顺序表的基本结构与接口实现

typedef int SLDatetype;
typedef struct seqlist
{
   SLDatetype* arr;
   int size;
   int capacity;
}SL;

arr是我们存储数组的首元素指针
size是顺序表中元素的个数
capacity是当前顺序表的容量大小

(1)尾插与尾删

0.初始化

void IniSL(SL* p)
{
   p->arr = (SLDatetype*)malloc(4 * sizeof(SLDatetype));
   if (!p->arr)
   {
   	printf("扩容失败");
   	perror(p);
   	return;
   }
   p->capacity = 4;
   p->size = 0;
   memset(p->arr, 0, 4*sizeof(SLDatetype));
}

1.扩容

 void CheckSl(SL*p)
{
   if (p->capacity <= p->size)
   {
   	p->capacity *= 2;
   	p->arr = (SLDatetype*)realloc(p->arr, sizeof(SLDatetype) * p->capacity);
   	if (!p->arr)
   	{
   		printf("扩容失败");
   		perror(p);
   		return;
   	}
   	p->capacity += 2;
   }
}

2.尾部增加

void SeqlistPushBack(SL* p, SLDatetype x)
{
   assert(p);
   //判断是否需要增容
   CheckSl(p);
   
   p->arr[p->size] = x;
   p->size++;
}

3.尾部删除

void SeqlistPopBack(SL* p)
{
   p->size--;
}

为什么不在后面替换为0?
因为没必要,只需要将他的size-1就可以不再访问后面的区域。

(2)头插与头删

1.头部增加

void SeqlistPushFront(SL* p, SLDatetype x)
{
   int tmp = p->size;
   CheckSl(p);
   for (; tmp >= 0; tmp--)
   {
   	p->arr[tmp + 1] = p->arr[tmp];
   }
   p->arr[0] = x;
   p->size++;
}

2.头部删除

void SeqlistPopFront(SL* p)
{
   int tmp = 0;
   for (tmp = 0; tmp < p->size - 1; tmp++)
   {
   	p->arr[tmp] = p->arr[tmp + 1];
   }
   p->size--;
}

(3)中插与中删

1.中间增加

void SeqlistPushIn(SL*p,SLDatetype x,int m)
{
   int tmp = p->size;
   CheckSl(p);
   for (; tmp >= m-1; tmp--)
   {
   	p->arr[tmp + 1] = p->arr[tmp];
   }
   p->arr[m-1] = x;
   p->size++;
}

2.中间删除

void SeqlistPopIn(SL* p, int m)
{
   for (int tmp = m-1; tmp < p->size-1; tmp++)
   {
   	p->arr[tmp] = p->arr[tmp + 1];
   }
   p->size--;
}

ps:通过观察上面的顺序表,我们不难发现头插与头删的时间复杂度O(n)
所以我们引入新的概念------链表,我们下一篇文章详细介绍

二.顺序表相关的练习

1.(leetcode)移除元素

在这里插入图片描述
解题

int removeElement(int* nums, int numsSize, int val) {
    int*p1=nums;
    int*p2=nums;
    int begin=0;
    int end=0;
    for(;begin<numsSize;begin++)
    {
        if(*(p1+begin)!=val)
        {
            *(p2+end)=*(p1+begin);
            end++;
        }
        else
        {}
    }
    return end;
}

分析
请添加图片描述

2.(leetcode)删除重复项(双指针,时间复杂的O(n),空间复杂度O(1))

在这里插入图片描述
解题

int removeDuplicates(int* nums, int numsSize) {
    int lock=0;//锁定的数
    int move=1;//移动的指针
    while(move<numsSize)
    {
        if(nums[lock]==nums[move])
        {
            move++;
        }
        else if(nums[lock]!=nums[move])
        {
            nums[++lock]=nums[move];
        }
    }
    return lock+1;

}

分析请添加图片描述

3.(leetcode)合并数组

在这里插入图片描述
解题

void merge(int* nums1, int nums1Size, int m, int* nums2, int nums2Size, int n) {
    int *pback = nums1 + nums1Size - 1;  // 指向 nums1 的最后一个位置
    int Max = m - 1;  // nums1 的有效数据的最后一个元素的索引
    int Min = n - 1;  // nums2 的最后一个元素的索引

    while (Max >= 0 && Min >= 0) {
        if (nums1[Max] >= nums2[Min]) {
            *pback-- = nums1[Max--];
        } else {
            *pback-- = nums2[Min--];
        }
    }

    // 如果 nums2 还有剩余元素,将其拷贝到 nums1 开头
    while (Min >= 0) {
        *pback-- = nums2[Min--];
    }
}

分析
请添加图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值