顺序表及其练习
一.顺序表
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--];
}
}
分析: