目录
一 概念及结构
二 顺序表接口实现
1 管理数据 增删查改(SeqList.c)
2 尾插(SeqList.c)
3 尾删(SeqList.c)
4 头插(SeqList.c)
5 头删(SeqList.c)
6 在pos位置插入x(SeqList.c)
7 在pos位置删除x(SeqList.c)
8 修改pos位置上的值(SeqList.c)
三 练习题(OJ)
1 移除元素
2 合并两个有序数组
3 删除有序数组的重复项
顺序表是用一段物理地址连续的存储单元依次存储数据元素的线性结构,一般情况下采用数组存 储。在数组上完成数据的增删查改
顺序表一般可以分为:
1. 静态顺序表:使用定长数组存储元素
2. 动态顺序表:使用动态开辟的数组存储
静态顺序表只适用于确定知道需要存多少数据的场景。静态顺序表的定长数组导致N定大了,空 间开多了浪费,开少了不够用。所以现实中基本都是使用动态顺序表,根据需要动态的分配空间 大小,所以下面我们实现动态顺序表。
先用SeqList.h 把我们想要的接口写进来
#pragma once
#define _CRT_SECURE_NO_WARNINGS 1
#pragma once
#include
#include
#include
// 动态顺序表
typedef int SLDataType;
typedef struct SeqList
{
SLDataType* a;
int size; // 存储有效数据个数
int capacity; // 空间大小
}SL;
// 管理数据 -- 增删查改
void SLInit(SL* ps);
void SLDestroy(SL* ps);
void SLPrint(SL* ps);
void SLCheckCapacity(SL* ps);
// 头插头删 尾插尾删
void SLPushBack(SL* ps, SLDataType x);
void SLPopBack(SL* ps);
void SLPushFront(SL* ps, SLDataType x);
void SLPopFront(SL* ps);
// 返回下标,没有找打返回-1
int SLFind(SL* ps, SLDataType x);
// 在pos位置插入x
void SLInsert(SL* ps, int pos, SLDataType x);
// 删除pos位置的值
void SLErase(SL* ps, int pos);
//修改
void SLModify(SL* ps, int pos, SLDataType x);
#include"SeqList.h"
//初始化
void SLInit(SL* ps)
{
assert(ps);//断言 防止是空指针
ps->a = (SLDataType*)malloc(sizeof(SLDataType) * 4);
if (ps->a == NULL)
{
perror("malloc failed");
exit(-1);
//return;
}
ps->size = 0;
ps->capacity = 4;
}
//销毁
void SLDestroy(SL* ps)
{
assert(ps);
free(ps->a);
ps->a = NULL;
ps->capacity = ps->size = 0;
}
//打印
void SLPrint(SL* ps)
{
assert(ps);
for (int i = 0; i < ps->size; i++)
{
printf("%d ", ps->a[i]);
}
printf("\n");
}
//扩容
void SLCheckCapacity(SL* ps)
{
assert(ps);
// 满了要扩容
if (ps->size == ps->capacity)
{
SLDataType* tmp = (SLDataType*)realloc(ps->a, ps->capacity * 2 *
(sizeof(SLDataType)));//一般都是1.5倍 2倍的扩
if (tmp == NULL)
{
perror("realloc failed");
exit(-1);
}
ps->a = tmp;
ps->capacity *= 2;
}
}
//尾插
void SLPushBack(SL* ps, SLDataType x)
{
assert(ps);
SLCheckCapacity(ps);//检查是否要扩容
ps->a[ps->size] = x;
ps->size++;
}
测试(Test.c)
void Test1()
{
SL s1;
SLInit(&s1);
SLPushBack(&s1, 1);
SLPushBack(&s1, 2);
SLPushBack(&s1, 3);
SLPushBack(&s1, 4);
SLPushBack(&s1, 5);
SLPrint(&s1);
SLDestroy(&s1);
}
int main()
{
Test1();
return 0;
}
//尾删
void SLPopBack(SL* ps)
{
assert(ps);
assert(ps->size > 0);
//ps->a[ps->size-1] = 0;
ps->size--;
}
//头插
void SLPushFront(SL* ps, SLDataType x)
{
assert(ps);
SLCheckCapacity(ps);
int tmp = ps->size;
while (tmp > 0)
{
ps->a[tmp] = ps->a[tmp - 1];
tmp--;
}
ps->a[0] = x;
ps->size++;
}
//头删
void SLPopFront(SL* ps)
{
assert(ps);
assert(ps->size > 0);
int begin = 1;
while (begin < ps->size)
{
ps->a[begin - 1] = ps->a[begin];
begin++;
}
ps->size--;
}
// 在pos位置插入x
void SLInsert(SL* ps, int pos, SLDataType x)
{
assert(ps);
assert(pos >= 0 && pos<= ps->size);
SLCheckCapacity(ps);
int end = ps->size;while (end > pos)
{
ps->a[end] = ps->a[end - 1];
end--;
}
ps->a[pos] = x;
ps->size++;
}
// 删除pos位置的值
void SLErase(SL* ps, int pos)
{
assert(ps);
assert(pos >= 0 && possize);
SLCheckCapacity(ps);
while (pos < ps->size)
{
ps->a[pos] = ps->a[pos + 1];
pos++;
}
ps->size--;
}
//修改pos位置的值
void SLModify(SL * ps, int pos, SLDataType x)
{
assert(ps);
assert(pos >= 0 && pos < ps->size);
ps->a[pos] = x;
}
总结:在实际的使用中 尾插尾删 头插头删 都可以使用SLInsert 和 SLErase 的方法
27. 移除元素 - 力扣(LeetCode)
int removeElement(int* nums, int numsSize, int val) {
int src = 0;
int dst = 0;
while (src < numsSize)
{
if (nums[src] != val)
{
nums[dst] = nums[src];
dst++;
}
src++;
}
return dst;
}
88. 合并两个有序数组 - 力扣(LeetCode)
思路就是将大的尾插到长的数组里
void merge(int* nums1, int nums1Size, int m, int* nums2, int nums2Size, int n) {
int end1 = m - 1; int end2 = n - 1; int end = m + n - 1;
while (end1 >= 0 && end2 >= 0)
{
if (nums1[end1] < nums2[end2])
{
nums1[end] = nums2[end2];
end2--;
}
else
{
nums1[end] = nums1[end1];
end1--;
}
end--;
}
while (end2 >= 0)
{
nums1[end] = nums2[end2];
end--;
end2--;
}
}
思路就是定义两个变量
int removeDuplicates(int* nums, int numsSize){
int src=0, dst = 0;
while(src < numsSize)
{
if(nums[src] == nums[dst])
{
src++;
}
else
{
dst++;
nums[dst] = nums[src];
src++;
}
}
return dst+1;
}