数据结构线性表的顺序结构存储的实现及其基本操作

嘻嘻,大家好,新人报到,之前逛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,本篇博客到此结束!江湖路远,有缘再见!

  • 3
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

「已注销」

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值