嘻嘻,大家好,新人报到,之前逛CSDN,一直很羡慕前辈们能够将自己所精通的知识分享给大家,今天我终于也可以发表属于自己的博客了,嘿嘿,很激动!
这篇博客是数据结构(C语言版)严蔚敏 吴伟民著 书中线性表一章的顺序存储结构实现及其基本操作的实现,发布的有些晚了,希望对大家有一些用吧,代码中还存在一些不完善的地方,希望大家发现了能给我指正一下,谢谢!(另外,因为学业的关系,未来发布的博客也都是以这类为主的,啥时候更新嘛,看情况喽!)
文章目录
1.头文件以及宏定义
#include <stdio.h>
#include <stdlib.h>
#define LIST_INIT_SIZE 5//线性表存储空间的初始分配量
#define LISTINCREMENT 5//线性表存储空间的分配增量
#define TRUE 1
#define ERROR 0
#define OK 1
#define OVERFLOW -1
2.typedef对部分数据类型的重命名
typedef int ElemType;//数据定义时使用
typedef int Status;//Status用于返回函数的状态
typedef struct
{
ElemType *elem;//存储顺序表的基地址
ElemType length;//顺序表的当前长度
ElemType listsize;//当前分配的存储容量
}Sqlist;
typedef int ElemType;//数据定义时使用
typedef int Status;//Status用于返回函数的状态
3.函数声明
Status InitList(Sqlist *L);//初始化线性表
Status DestroyList(Sqlist *L);//销毁线性表
Status ClearList(Sqlist *L);//清空线性表
Status ListEmpty(Sqlist *L);//判断线性表是否为空
Status ListLength(Sqlist *L);//判断线性表的长度
void tips();//菜单函数
void GetElem(Sqlist *L, ElemType position);//查找指定位置的元素
void LocateElem(Sqlist *L,ElemType n);//查找指定元素的位置
void PriorElem(Sqlist *L,ElemType n);//查找指定元素的前驱元素
void NextElem(Sqlist *L,ElemType n);//查找指定元素的后继元素
Status ListInsert(Sqlist *L,ElemType x,ElemType position);//插入元素
Status ListDelete(Sqlist * L,ElemType position);//删除指定位置的数字
void ListVisit(Sqlist *L);//打印线性表
4.菜单函数
void tips()
{
printf("1----初始化一个线性表\n");
printf("2----销毁线性表\n");
printf("3----清空线性表\n");
printf("4----判断线性表是否为空\n");
printf("5----求线性表长度\n");
printf("6----获取线性表中指定位置的元素\n");
printf("7----获取线性表元素的位置\n");
printf("8----求前驱\n");
printf("9----求后继\n");
printf("10---在线性表指定位置插入元素\n");
printf("11---删除线性表指定位置的元素\n");
printf("12---显示线性表\n");
printf("退出,输入一个负数\n");
}
5.初始化顺序表函数
分配内存空间后先检查是否初始化成功,若成功将线性表当前长度初始化为零,线性表总长度设置为LISTINCREMENT(宏定义的值),然后通过while循环依次在线性表中的连续存储空间中存储数据,并检查 数据是否重复,完成以上操作后返回OK,存储在标志K中,代表顺序表初始化初始化成功
Status InitList(Sqlist *L)
{
ElemType x;
L->elem=(ElemType *)malloc(LIST_INIT_SIZE*sizeof(ElemType));
if(!L->elem)
{
printf("初始化线性表失败\n");
exit(OVERFLOW);//存储空间满了,退出整个程序
}
L->length=0;
L->listsize=LIST_INIT_SIZE;
printf("请输入数字,退出输入负数\n");
while(TRUE)
{
printf("输入第%d个数字\n",L->length+1);
if(L->length<L->listsize)
{
scanf("%d",&x);
if(x>=0)
{
if(L->length==0)
{//当线性表长度为0时,一定不会有重复的元素,可以直接将x存储
L->elem[L->length]=x;
L->length++;
}else//判断是否重复
{
ElemType i,k=1;
for(i=0;i<L->length;i++)
{//遍历已存储的数据,判断是否有与x重复的数据
if(x==L->elem[i])
k=0;
}
if(k==0)
{
printf("输入了重复元素,请重新输入\n");
}else
{
L->elem[L->length]=x;
L->length++;
}
}
}
}else
{
printf("超出长度,请增加线性表长度再赋值\n");
break;
}
if(x<0)//为了退出初始化函数
break;
}
return OK;
}
6.销毁线性表
释放系统分配的连续的内存空间,将基地址赋值为NULL,线性表当前长度赋值为0,总长度赋值为0,并返回一个宏定义的值ERROR给K,代表线性表已销毁。
Status DestroyList(Sqlist *L)
{
free(L->elem);
L->elem=NULL;
L->length=0;
L->listsize=0;
return ERROR;
}
7.清空线性表
清空线性表只需要将线性表的当前长度设置为0即可,不用删除其中存储的元素,因为以后为线性表赋值会覆盖原来的数据,省去了删除操作,最后返回一个宏定义的值ERROR给K,代表线性表为空
Status ClearList(Sqlist *L)
{
L->length=0;
return ERROR;
}
8.判断线性表是否为空
只需要判断线性表的当前长度是否为0,并返回相应的状态即可
Status ListEmpty(Sqlist *L)
{
if(L->length!=0)
return OK;
else
return ERROR;
}
9.判断线性表的长度
返回线性表的当前长度length即可
Status ListLength(Sqlist *L)
{
printf("线性表的长度为%d\n",L->length);
return L->length;
}
10.查找指定 位置 的 元素
用户输入想要查找的位置,在函数中先判断位置是否合法,(位置是否大于0并小于等于length) 如果合法输出所在位置的元素,不合法输出未找到该位置,并结束调用
void GetElem(Sqlist *L, ElemType position)
{//位置的取值肯定是第一个(0)到最后一个(L->length)之间元素
if(position>0&&position<=L->length)
printf("你所查找位置的元素值为%d\n",(*L).elem[position-1]);
else
printf("该位置不存在于线性表中\n");
}
11.查找指定 元素 的 位置
先设置一个标志k=0;通过for循环遍历线性表,如果存在该元素,则输出该元素的位置,并令k=1;break出for循环,此时判断k的值是否改变,如果未在线性表中找到该元素,则k的值不会改变
void LocateElem(Sqlist *L,ElemType n)
{
ElemType i,k=0;//k=0代表未找到该元素
for(i=0;i<L->length;i++)
{
if(n==L->elem[i])
{ //元素在线性表中的位置为索引+1;可对比数组
printf("该元素出现在线性表的第%d个位置上\n",i+1);
k=1;
break;
}
}
if(k==0)
printf("未找到该元素\n");
}
12.求前驱元素
设置一个标志K=-1,先判断所查找元素n的值是否等于线性表的第一个元素,如果是,则令K=0;然后进入for循环,遍历第二个到最后一个元素,判断n是否与他们相等,如果是,令k=i,并输出;退出循环,此时判断k的值,k没有改变代表线性表中不存在这个元素,K=0代表n为线性表第一个元素,不存在前驱元素
void PriorElem(Sqlist *L,ElemType n)
{
ElemType i,k=-1;//k=-1代表未找到该元素
if(L->elem[0]==n)
{
k=0;
}else
{
for(i=1;i<L->length;i++)
{
if(n==L->elem[i])
{
printf("该元素的前驱元素是%d\n",L->elem[i-1]);
k=i;
break;
}
}
}
if(k==0)
printf("该元素为顺序表第一个元素,不存在前驱\n");
else if(k==-1)
printf("顺序表中不存在该元素\n");
}
13.求后继元素
设置一个标志K=-1,先判断所查找元素n的值是否等于线性表的最后一个元素,如果是,则令K=0;然后进入for循环,遍历第一个直到倒数第二个元素,判断n是否与他们相等,如果是,令K=i,并输出;退出循环,此时判断k的值,k没有改变代表线性表中不存在这个元素,K=0代表n为线性表最后一个元素,不存在后继元素。
void NextElem(Sqlist *L,ElemType n)
{
ElemType i,k=-1;//k=-1代表未找到该元素
if(L->elem[L->length-1]==n)
{
k=0;
}else
{
for(i=0;i<L->length-1;i++)//只有0~l->length-2上存在后继元素
{
if(n==L->elem[i])
{
printf("该元素的后继元素是%d\n",L->elem[i+1]);
k=i;
break;
}
}
}
if(k==0)
printf("该元素为顺序表最后一个元素,不存在后继\n");
else if(k==-1)
printf("顺序表中不存在该元素\n");
}
14.在指定位置上插入元素
首先判断插入位置是否合法,若不合法直接退出调用,并给出相应提示;然后判断该元素是否与线性表中的元素重复,若重复退出调用,并给出相应提示;接下来判断线性表存储空间是否足够;如果满了则为其增加新的内存空间;之后将插入位置之后的(包括插入位置的元素依次向后移一位),最后在要插入的位置插入元素(例如:插入位置如果是第一个,那么原先的第一个元素及其之后的就后退一位)
Status ListInsert(Sqlist *L,ElemType n,ElemType position)
{
ElemType i;
ElemType * newbase;
if(position<=0||position>L->length)
{
printf("插入位置不存在\n");
return ERROR;
}
for(i=0;i<L->length;i++)
{
if(n==L->elem[i])
{
printf("该元素已存在,插入失败\n");
return ERROR;
}
}
if(L->length>=L->listsize)
{//相当于在原先的房子上又盖了几层
newbase=(ElemType *)realloc(L->elem,(L->listsize+LISTINCREMENT)*sizeof(ElemType));
if(!newbase)
{
printf("分配失败\n");
exit(OVERFLOW);
}
L->elem=newbase;
L->listsize+=LISTINCREMENT;
}
for(i=L->length;i>=position;i--)
{//未插入前最后一个位置是L.length-1;要插入的话就得向后移一位
L->elem[i]=L->elem[i-1];
}
L->elem[position-1]=n;
L->length++;
printf("插入成功\n");
return OK;
}
15.删除指定位置上的元素
首先判断删除位置是否合法,若不合法直接退出调用,并给出相应提示;
然后将所删除位置之后的元素(不包括所删除的位置)从前往后,依次向前移一位,最后将线性表的长度-1.
Status ListDelete(Sqlist * L,ElemType position)
{
ElemType i;
if(position<=0||position>L->length)
{
printf("该位置不存在\n");
return ERROR;
}
for(i=position-1;i<L->length;i++)
{
L->elem[i]=L->elem[i+1];
}
L->length--;
printf("删除成功\n");
return OK;
}
16.主函数
主函数只负责调用函数,线性表的操作通过具体函数实现(其中,通过while语句和switch语句实现对于不同函数的调用,并通过if-else if语句实现对于用户输入数据异常的处理,在switch的分支中,通过设置标志k来判断线性表是否为空或者是否初始化)
int main()
{
ElemType i,k=0,x;//k表示顺序表的状态,k=0代表线性表未初始化 k=1代表初始化成功
ElemType position;//position用于接收用户输入的位置
ElemType L_length; //线性表长度
tips();
while(TRUE)//使用户可以进行持续的操作
{
printf("请输入你的选择\n");
scanf("%d",&i);
if(i<0)
{
printf("成功退出\n");
break;
} else if(i>=1&&i<=12)
{
switch(i)
{
case 1://初始化线性表
k=InitList(&L);
if(k==OK)
printf("初始化线性表成功\n");
break;
case 2://销毁线性表
if(!k)
{
printf("线性表为空或未初始化\n");
break;
}else
{
k=DestroyList(&L);
if(k==ERROR)
printf("销毁成功\n");
else
printf("销毁失败\n");
break;
}
case 3://清空线性表
if(!k)
{
printf("线性表为空或未初始化\n");
break;
}else
{
k=ClearList(&L);
if(k==ERROR)
printf("线性表已清空\n");
else
printf("清空线性表失败\n");
break;
}
case 4://判断线性表是否为空
if(!k)
{
printf("线性表未初始化\n");
break;
}else
{
k=ListEmpty(&L);
if(k==OK)
printf("线性表不为空\n");
else
printf("线性表为空\n");
break;
}
case 5://判断线性表的长度
if(!k)
{
printf("线性表为空或未初始化\n");
break;
}else
{
L_length=ListLength(&L);
break;
}
case 6://查找指定位置的元素
if(!k)
{
printf("线性表为空或未初始化\n");
break;
}else
{
printf("请输入你所查找的位置\n");
scanf("%d",&position);
GetElem(&L,position);
break;
}
case 7://查找指定元素的位置
if(!k)
{
printf("线性表为空或未初始化\n");
break;
}else
{
printf("请输入你所查找的元素\n");
scanf("%d",&x);
LocateElem(&L,x);
break;
}
case 8://查找指定元素的前驱元素
if(!k)
{
printf("线性表为空或未初始化\n");
break;
}else
{
printf("请输入数字,将输出其前驱\n");
scanf("%d",&x);
PriorElem(&L,x);
break;
}
case 9://查找指定元素的后继元素
if(!k)
{
printf("线性表为空或未初始化\n");
break;
}else
{
printf("请输入数字,将输出其后继\n");
scanf("%d",&x);
NextElem(&L,x);
break;
}
case 10://插入元素
if(!k)
{
printf("线性表为空或未初始化\n");
break;
}else
{
printf("请输入所要插入的数字\n");
scanf("%d",&x);
printf("请输入你所插入的位置\n");
scanf("%d",&position);
ListInsert(&L,x,position);
break;
}
case 11://删除指定位置的数字
if(!k)
{
printf("线性表为空或未初始化\n");
break;
}else
{
printf("请输入所要删除的位置\n");
scanf("%d",&position);
ListDelete(&L,position);
break;
}
case 12://显示线性表
if(!k)
{
printf("线性表为空或未初始化\n");
break;
}else
{
ListVisit(&L);
break;
}
}
}else
{
printf("输入错误\n");//遇见非数值时会出现死循环
}
}
return 0;
}
OK,本篇博客到此结束!江湖路远,有缘再见!