线性表(♪含C实现基本操作♪)
严老师《数据结构》一书中说提出的第一种结构就是线性表,这也正是因为它是数据结构中最简单的数据存储结构。
本篇就简单介绍相关的基本操作的原理及相应的C代码。
--------------------------------------基本原理和概念都懂的宝宝可以直接往下看代码----------------------------
顺序存储结构我们再熟悉不过了,比如数组;
而链式存储结构可更大程度的利用空间,通过指针记录下一个节点的地址,这样即使异地恋他们也不会迷失哈哈(如上图所示)。~这儿有链表蛤~------>https://blog.csdn.net/qq_38193883/article/details/93322720
因此用链式存储结构时定义线性表,需要利用结构体,里面记录数据,指针,为了方便操作,还需要记录线性表的长度与空间。
(不要慌张,先看看两者的区别)
因此顺序存储时酱紫定义:
//定义存储结构
typedef struct Link{
int *elem;//表的基址
int number;//表的长度,即元素个数
int size;//表的空间
}List;
插入操作: (先看图意会下)
步骤: 先找到插入位置------>从插入位置开始,到最后一个元素为止,逐个后移-------->目标位置已经被腾空,放数据即可。
操作时应注意:移动时为了防止值被覆盖,要从尾部开始后移,把值赋值给后面的位置。(如果从插入位置开始正序后移的话,就错啦)
上核心代码(更详细的往下扒拉哈~):
//p为插入位置,rear为尾指针
for(rear;rear>=p;rear--)
{
*(rear+1)=*(rear);
}
//此时rear已经移动到p的位置
*p=data;//或者写*rear=data;
删除操作:
步骤:先找到删除位置-------->从删除位置开始,到左后一个元素为止,逐个前移
操作时:(注意与插入操作对比区别)正序前移即可,即从删除位置开始,赋值为它后面的值。
上核心代码(详细的在下面哦~):
//p为删除位置,rear为尾指针
for(p;p<rear;p++)
{
*(p)=*(p+1);//从删除位置p开始赋值为后面的值
}
以下是一些一些常用的操作,及测试案例:
包括:
-
线性表的声明定义
-
线性表的插入,删除
-
线性表的清空,销毁
-
获取特定位置元素及前驱后继
-
两个线性表的合并
-
遍历输出
-
查找某元素在表中第一次(最后一次)出现的位置
//顺序表的基本操作
#include<stdio.h>
#include<stdlib.h>
#include<malloc.h>
#define initsize 100 //初始空间分配量
#define increase 10 // 分配增量
//线性表的相关操作(动态分配的顺序存储结构)
//定义存储结构
typedef struct Link{
int *elem;
int number;
int size;
}List;
//(1)创建一个空表(初始化)InitList(&L)
int InitList(List &L){
L.elem=(int *)malloc(initsize*sizeof(int));//分配初始空间
if(!L.elem){return -1;}
L.number=0;//表内元素数目初始化为0
L.size=initsize;
return 1;
}
//(2)销毁列表DestroyList(&L)
int DestroyList(List &L){
L.size=0;
L.number=0;
L.elem=NULL;
//或直接free(&L);
return 1;
}
//(3)清空列表ClearList(&L)
bool ClearList(List &L)
{
if(L.number==0){
printf("表已清空~\n");
return true;//表内元素数目为0
}
L.number=0; //否则将元素个数置为0
printf("ok!\n");
return true;
}
//在表L的第pos个位置之前插入数据data
int Insert(List &L,int pos,int data)
{
//pos的合法位置是1~len+1;其中pos=1表示插头,pos=len+1表示插尾
if(pos<1||pos>L.number+1) return 0;//先判断插入位置的合法性
//还需判断空间是否充足 ,数据填满时需扩展空间再分配
if(L.number>=L.size)
{
int *newid=(int *)realloc(L.elem,L.size+increase*sizeof(int));
if(!newid) return 0;
L.elem=newid;
L.size+=increase;
}
int *p= &L.elem[pos-1];//p为表中插入位置,与用户默认值相差1;
int *rear=&L.elem[L.number-1];//rear为表中最后一个元素的位置;
//接下来从插入位置开始到最后一个元素为止逐个后移,腾出插入位置即L.elem[pos-1]放data;
for(rear;rear>=p;rear--)
{
*(rear+1)=*(rear);
}
*p=data;//其实这里也可以写*rear=data;
L.number++;//插入后元素个数增加一
return 1;
}
//删除给定位置元素DeleteList(&L,pos,e)
int DeleteList(List &L,int pos,int &e)
{
//也是先判断位置是否合理 :1=<pos<=L.number;
if(pos<1||pos>L.number) return 0;
int *p= &L.elem[pos-1];//p为表中要删除的位置,与用户默认值相差1;
e=*p;//先保存所删除的值
int *rear=&L.elem[L.number-1];//rear为表中最后一个元素的位置;
//接下来从删除位置后一个开始到最后一个位置为止,逐个前移一位
for(p;p<rear;p++)
{
*(p)=*(p+1);
}
L.number--;//删除后元素个数减少一
return 1;
}
//获取给定位置元素以及直接前驱直接后驱GetElem(L,i,&e)
int GetElem(List &L, int i, int &e,int &pri_e,int &next_e) {
if(L.number==0){
printf("抱歉,当前线性表是空表\n");
return -1;
}
if(i<1 || i>L.number){
printf("当前位置超出了线性表的范围\n") ;
return -1;
}
pri_e=L.elem[i - 2];
e = L.elem[i - 1];
next_e=L.elem[i];
return 0;
}
//遍历输出
void print(List &L) {
for (int i = 0; i < L.number; i++) {
printf("%d ",L.elem[i]);
}
printf("\n");
}
//查找某元素在表中第一出现的位置
//若想查看最后一次出现的位置只需将i倒序遍历即可
int LocateList(List L,int e)
{
int i=0;
for(i;i<L.number;i++)
{
if(L.elem[i]==e)
{
return i+1;
}
}
if(i==L.number)
{
return -1;
}
}
//归并两表(不要求两表提前有序,且未去重)
void MergeList(List La,List Lb,List &Lc)
{
int *a=La.elem;
int *b=Lb.elem;
int *c=Lc.elem=(int *)malloc(initsize*sizeof(int));
if(!Lc.elem){
return ;
}
Lc.size=Lc.number=La.number+Lb.number;
int *ar=a+La.number-1;//ar表示遍表a的尾指针
int *br=b+Lb.number-1;//br同理
while(a<=ar&&b<=br)
{
if(*a<=*b)
{
*c++ = *a++;
}
else{
*c++ = *b++;
}
}//跳出循环可额能有两种情况:a或b提前遍历结束 ab都遍历结束
//则需把剩余的都加进c表中
while(a<=ar){
*c++ = *a++;
}
while(b<=br){
*c++ = *b++;
}
}
//测试
int main()
{
//声明表;
List La;
List Lb;
//初始化
InitList(La);
InitList(Lb);
//插入元素
printf("La的变化过程\n");
for(int i=1;i<=5;i++)
{
Insert(La,i,2*i);
print(La);
}
printf("Lb的变化过程\n");
for(int i=1;i<=5;i++)
{
Insert(Lb,i,i-1);
print(Lb);
}
//合并
List Lc;
InitList(Lc);
printf("\n合并La与Lb===>Lc表: \n");
MergeList(La,Lb,Lc);
print(Lc);
//元素第一次出现的位置
printf("\n元素2在表Lc中第一次出现的位置是%d\n",LocateList(Lc,2));
//查找前驱后继
int e,pri_e,next_e;
GetElem(Lc,3,e,pri_e,next_e);
printf("\n在表Lc中第三个位置的元素是%d,它前面是%d,后面是%d\n",e,pri_e,next_e);
//删除元素
int del;
DeleteList(Lc,5,del);
printf("\n删除表Lc中第5个位置的元素%d\n",del);
print(Lc);
//清空
printf("\n清空LC\n");
ClearList(Lc);
print(Lc);
return 0;
}
测试结果展示(开心,蛤蛤~):
正经致谢:-------->