1.线性表
2.顺序表
2.1概念及结
![](https://i-blog.csdnimg.cn/blog_migrate/144ed8bac44c10bb138c7b7b011f8426.png)
通常我们并不使用定长的顺序表,因此只需了解下即可。
2. 动态顺序表:使用动态开辟的数组存储。
下面我们来具体介绍一下动态顺序表:
首先是类型的声明:
// 确定顺序表内部存放数据的类型;
typedef int SLDateType;
//定义顺序表类型;
typedef struct SeqList
{
SLDateType* a;
int k;
int capacity;
}SeList;
其中有动态开辟的数组,有效数据个数,以及数组容量。
初始化顺序表:
给动态开辟的数组空间 初始化开辟3个元素的空间。
此时数组容量为3,有效元素个数为0;
void SeqListInit(SeList* ps)
{
ps->a = (SLDateType*)malloc(3 * sizeof(SLDateType));
if (ps->a == NULL)
{
perror("malloc");
exit(-1);
}
ps->capacity = 3;
ps->k = 0;
}
销毁顺序表;
释放动态开辟的数组空间,然后容量与有效元素个数都为0即可。
//销毁顺序表;
void SeqListDestroy(SeList* ps)
{
free(ps->a);
ps->a = NULL;
ps->capacity = 0;
ps->k = 0;
}
打印顺序表
只需要遍历一遍数组打印即可;
//打印顺序表;
void SeqListPrint(SeList* ps)
{
int i = 0;
for (i = 0; i < (ps->k); i++)
{
printf("%d ",*(ps->a+i));
}
}
顺序表的扩容
若有效元素的个数与容量相等则需要用realloc扩容,每次扩容,容量加倍。
//扩容函数;
void increaseSeqList(SeList* ps)
{
if ((ps->k) == (ps->capacity))
{
SLDateType* tmp = (SLDateType*)realloc(ps->a, 2 * (ps->capacity) * (sizeof(SLDateType)));
if (tmp == NULL)
{
perror("realloc");
exit(-1);
}
ps->a = tmp;
ps->capacity *= 2;
}
}
顺序表的尾增:
首先要判断数组需不需要扩容;然后输入需要尾增的数据,直接尾增进去即可;
//尾增
void SeqListPopBack(SeList* ps)
{
//检查是否需要扩容;
increaseSeqList(ps);
//输入尾增数据;
int n = 0;
scanf("%d", &n);
//尾增;
ps->a[ps->k] = n;
ps->k++;
}
尾删
在k大于0的情况下直接有效元素数量k--即可;
//尾删
void SeqListPushBack(SeList* ps)
{
assert(ps);
assert(ps->k >0);
ps->k--;
}
头删
依次进行挪动覆盖在K--即可;
//头删;
void SeqListPushFront(SeList* ps)
{
assert(ps);
assert(ps->k > 0);
int i = 0;
for (i = 0; i < ps->k-1; i++)
{
ps->a[i] = ps->a[i + 1];
}
ps->k--;
}
头增
分为两种情况若k==0则不需要扩容,也不需要挪动数据,直接插入即可,然后K++即可;
若k不等与0:首先需要检查数组容量,然后需要从后往前挪动数据,在头插入数据 ,k++即可;
//头增;
void SeqListPopFront(SeList* ps)
{
//检查容量
increaseSeqList(ps);
int n = 0;
//不需要数据的挪动;
if (ps->k == 0)
{
scanf("%d", &n);
ps->a[0] = n;
ps->k++;
return;
}
//需要挪动覆盖:
int i = 0;
for (i = ps->k-1; i >=0; i--)
{
ps->a[i + 1] = ps->a[i];
}
scanf("%d", &n);
ps->a[0] = n;
ps->k++;
}
顺序表查找
遍历一遍数组若可以找到目标数据则返回其下标,若不能则返回-1;
// 顺序表查找
int SeqListFind(SeList* ps, SLDateType x)
{
assert(ps->k > 0);
int i = 0;
for (i = 0; i < ps->k; i++)
{
if (ps->a[i] == x)
{
return i;
}
}
return -1;
}
顺序表在pos位置处插入x;
首先检查容量; 之后和头插一样分为两种情况:若k==0则不需要挪动数据直接插入,然后k++即可;若k不等于0则需要挪动数据再插入,然后K++;
// 顺序表在pos位置插入x
void SeqListInsert(SeList* ps, int pos, SLDateType x)
{
//检查容量
increaseSeqList(ps);
//pos一定是大于等于0的数据;
assert(pos >= 0);
//k==0不需要挪动数据;
if (ps->k == 0)
{
ps->a[pos] = x;
ps->k++;
return;
}
//k不等于0,需要挪动数据;
int i = 0;
for (i=ps->k-1;i>=pos;i--)
{
ps->a[i + 1] = ps->a[i];
}
ps->a[pos] = x;
ps->k++;
}
顺序表在pos位置处删除数据;
直接用后面的数据挪动覆盖,然后k--即可;
// 顺序表删除pos位置的值
void SeqListErase(SeList* ps, int pos)
{
assert(ps->k > 0);
int i = 0;
for (i = pos; i < ps->k-1; i++)
{
ps->a[i] = ps->a[i + 1];
}
ps->k--;
}
leetcode题目
1.移除元素;leetcode链接:27. 移除元素 - 力扣(LeetCode)
分析: 此题要分为两种情况,若val在【0,n-2】位置处则需要进行数据的挪动,若在最后一个位置则不需要挪动,直接n--;
int removeElement(int* nums, int numsSize, int val)
{
int i=0;
int n=numsSize;
//若为空数组:
if(n==0)
{
return 0;
}
//在第一个数据和倒数第二个数据之间找val
for(i=0;i<n-1;i++)
{
//找到,则将这个元素后面的数据进行向前挪动,
if(nums[i]==val)
{
int j=i;
for(j;j<n-1;j++)
{
nums[j]=nums[j+1];
}
//数组数据个数n--;
n--;
//i--防止挪动后的数据也为val,需要退回去对此位置重检查;
i--;
}
}
//若最后一个数据是val则不需要挪动,直接n--;
if(nums[n-1]==val)
{
n--;
}
return n;
}
2.删除排序数组中的重复项 ;leetcode链接:26. 删除有序数组中的重复项 - 力扣(LeetCode)
分析:只需要对数据进行遍历从后一个位置开始找相同的元素,若到相同的元素,则用后面的数据进行挪动覆盖;
int removeDuplicates(int* nums, int numsSize)
{
int n=numsSize;
int i=0;
//对数组进行遍历;
for(i=0;i<n;i++)
{
int j=0;
//从后一个位置开始找是否有重复的
for(j=i+1;j<n;j++)
{
if(nums[i]==nums[j])
{
//若有则将后面的数据向前挪动,去除这个数据;如果是最后一个元素,则不需要挪动
for(j;j<n-1;j++)
{
nums[j]=nums[j+1];
}
n--;
//j--防止挪动后的数据又和该数据相同,需要重新对该位置检查;
j--;
//i--对i当前的位置也要退回去重新检查;
i--;
}
}
}
return n;
}
3.合并两个有序数组; leetcode链接:88. 合并两个有序数组 - 力扣(LeetCode)
分析:此题很多人会对两个数组从前往后分别进行比较然后放入,但是这样会导致放入
num1时需要对元素整体后移动,比较麻烦。可以从后往前对两个数组元素进行比较,找较大的数
据从尾部放入num1,这样避免了对元素的移动。
void merge(int* nums1, int nums1Size, int m, int* nums2, int nums2Size, int n)
{
//num1的最后元素的下标;
int end1=m-1;
//num2的最后元素的下标;
int end2=n-1;
//合并后的数组的最后元素的下标;
int end=m+n-1;
//两个数组都没遍历完时,对两个数组元素分别进行比较,将较大的那个放入;
while(end1>=0&&end2>=0)
{
if(nums1[end1]>nums2[end2])
{
nums1[end--]=nums1[end1--];
}
else
{
nums1[end--]=nums2[end2--];
}
}
//比较完后若nums2还没有遍历完将nums2剩下的元素放入;
while(end2>=0)
{
nums1[end--]=nums2[end2--];
}
}