[数据结构] - 使用C语言实现顺序表操作

[数据结构]-使用C语言实现顺序表操作


顺序表的抽象数据类型

ADT  线性表(List)
Data
	ElemType *elem; 	//声明基地址
	int length;	//线性表中的长度
	int maxsize; //线性表最大存储单元
Operation
	int initSql(sqList *L);								    //初始化顺序表 
	int insertElem(sqList *L, int item, ElemType e);		//插入元素 
	int getElem(sqList *L,int item,ElemType *e);			//获取元素 
	int searchElem(sqList *L,ElemType e);					//查找元素 
	int deleteElem(sqList *L,int item);						//删除元素 c
	void showList(sqList *L);							    //显示所有数据 
	int popBack(sqList *L);								    //尾删 
	int popHead(sqList *L);								    //头删 
	int pushBack(sqList *L,ElemType e);						//尾插 
	int pushHead(sqList *L,ElemType e);						//头插 
endADT

顺序表的C语言代码的实现

引入头文件
//====================================================================
#include<stdio.h>
#include<malloc.h>
#include<stdlib.h>
//====================================================================
#include<malloc.h> // 引入malloc函数

malloc函数
	功能:声明一段连续的内存空间
	返回值:
		成功 内存空间的指针
		失败 返回 null
定义常量
//====================================================================
// 定义返回值的状态 
#define TRUE        1
#define FALSE       0
#define OK          1
#define ERROR       0
#define INFEASIBLE -1
#define OVERFLOW   -2

# define MAXSIZE 100 	// 设置线性表最大长度c

typedef int ElemType;	
//====================================================================

一开始看到这个ElemType的时候不太理解他是做什么的,毕竟是跟着课本学的,上面既没有给出定义方式也没有给出解释。后来参考各种资料发现了ElemType的具体情况。typedef是用来定义别名的声明,就是将int类型定义一个别名叫做ElemType。我个人感觉有点像是把int类型重映射到ElemType 。那这个声明有什么作用能,一般顺序表中的元素是同一类型的,如果我们在接下来的代码块中直接使用int类型的话,如果哪天我想换成char类型,那岂不是得把所有int类型的声明都要更改成char类型。所以为了方便,在这里找一个代理ElemType,来代替int行使权力。如果我想将数据改成char类型的只需要把定义由typedef int ElemType; 改成 typedef char ElemType; 就欧耶了。

声明一个顺序表的结构体
//====================================================================
typedef struct {
	ElemType *elem; 	//声明基地址
	int length;	//线性表中的长度
	int maxsize; //线性表最大存储单元
}sqList; 
//====================================================================

struct ==> 声明一个结构体;typedef ==> 定义一个别名,别名叫做sqList

初始化方法
//====================================================================
int initSql(sqList *L);								   //初始化顺序表 
int insertElem(sqList *L, int item, ElemType e);		 //插入元素 
int getElem(sqList *L,int item,ElemType *e);			 //获取元素 
int searchElem(sqList *L,ElemType e);					//查找元素 
int deleteElem(sqList *L,int item);						//删除元素 c
void showList(sqList *L);							   //显示所有数据 
int popBack(sqList *L);								   //尾删 
int popHead(sqList *L);								   //头删 
int pushBack(sqList *L,ElemType e);						//尾插 
int pushHead(sqList *L,ElemType e);						//头插 
//====================================================================
初始化一个顺序表
//====================================================================


int initSql(sqList *L){
	/**************************************
	* SqList L: 顺序表对象 
	***************************************/

	L->elem = (ElemType *)malloc(MAXSIZE*sizeof(ElemType));
	
	if(!L->elem){
		return OVERFLOW; //-2
		
	}else{
		L->length = 0;
		L->maxsize = MAXSIZE;
		return OK; //1
	} 

}
//====================================================================

*是取地址的意思 将形参L的地址作为初始化方法的参数传进来(L是一个结构体);OK OVERFLOW 是上面定义的全局变量 ; malloc 在上面引入了#include<malloc.h> 功能:分配内存空间,并返回一个指向这个内存空间的指针 ==> L.elem

将一个值插入顺序表
//====================================================================

int insertElem(sqList *L,int item, ElemType e){
	/**************************************
	* SqList L: 顺序表对象 
	* int item:要插入的值的item 
	* ElemType e:将值赋给哪个变量 在这里因为int重定向给ElemType ==> int *a 
	*	为什么不用*? 
	*	因为他是一个元素值,我不想让顺序表的对应位的指针指向这个变量,我想让顺序表的对应的值就是这个值 
	***************************************/
	int i;

	// item 在否?
	if(item<1||item>L->length+1){ 
		return ERROR; 
	} 
	// length够否?
	if(L->length >= L->maxsize){
		return OVERFLOW;
	} 
	
	//item后的全体数据 后撤1位 
	for(i=L->length;i>item-1;i--){
		/* 
		* 数组从0开始,所以要-1;
		* 从最后一位向前依次挪,挪到item-1位,不可以从item位-1开始向后挪; 
		* length-1其实默认可顺序表还有剩余空间,前面已经把没空给排出来 
		*/
		L->elem[i] = L->elem[i-1];
	}
	
	// 挪完以后留出空了,这时候就可以放数据了c
	L->elem[item-1] = e;
	L->length++;
	return OK;

} 
//====================================================================

判断item在否?的条件, 1<= item <= L.length+1 因为我可以往第一位插也可以往最后一位插

从一个顺序表中取值
//====================================================================
int getElem(sqList *L,int item,ElemType *e){
	/**************************************
	* SqList L: 顺序表对象 
	* int item:要获取的值的item 
	* ElemType *e:将值赋给哪个变量 在这里因为int重定向给ElemType ==> int *a 
	*	为什么用*? 这就又用到哪个映射的名词,相当于e的指针指向了item位的元素的地址(取值应该都可以这么用) 
	***************************************/

	// item 在否?
	 if(item<1||item>L->length) {
	 	return ERROR; //0
	 }else{
	 	*e = L->elem[item-1];
	 }

}
//====================================================================

先判断这个item有没有超出这个表的范围,可以的话将他赋值给e

从一个顺序表中查找数据
//====================================================================
int searchElem(sqList *L,ElemType e){
	int i;
	
	// 遍历 
	for(i=0;i<L->length;i++){	
		if(L->elem[i] == e){	
			return i;
		} 
	}
	return FALSE;
} 
//====================================================================
从一个顺序表中删除元素
//====================================================================
int deleteElem(sqList *L,int item){
	int j;
	

	// item在否?
	if(item<1||item>L->length){
		return ERROR;
	}
	
	//全体前移,这时候就得从item-1+1的位置开始向前移动。 
	for(j=item;j<=L->length+1;j++){
		L->elem[j-1] = L->elem[j];
		L->length = L->length-1;
	}
	return OK;

} 
//====================================================================
展示顺序表的所有数据
//====================================================================
void showList(sqList *L){
	int i;
	for( i=0; i<L->length; i++){
		printf("%d",L->elem[i]);
	}
		printf("\n");
} 
//====================================================================

特殊玩法

头插法插入数据

从数据表的头部进行插入数据

//====================================================================
int pushHead(sqList *L,ElemType e){
	int i;
	if(L->length>=L->maxsize){
		return OVERFLOW;
	}else{
		for(i=L->length;i>0;i--){
			L->elem[i] = L->elem[i-1];
		}
		L->elem[0] = e;
		L->length++;
	}
} 
//====================================================================
尾插法插入数据

从数据表的尾部进行插入数据

//====================================================================
int pushBack(sqList *L,ElemType e){
	if(L->length>=L->maxsize){
		return OVERFLOW;
	}else{
		L->elem[L->length]=e;
		L->length++;
	}
} 
//====================================================================
头删除

从数据表的头部进行删除数据

//====================================================================
int popHead(sqList *L){
	int i;
	if(L->length==0){
		return ERROR;
	}else{
		for(i=0;i<L->length-1;i++){
			L->elem[i] = L->elem[i+1];
		}
		L->length--;
	}
} 
//====================================================================
尾删除

从数据表的尾部进行删除数据

//====================================================================
int popBack(sqList *L){
	if(L->length==0){
		return ERROR;
	}else{
		L->length--;
	}
} 
//====================================================================
主方法
void main(){

	ElemType returnN;
	int i;
	sqList L;

	if(initSql(&L)==1) {
		printf("初始化完成\n");
		printf("初始化(initSql)elem=%d\n",L.elem);
		printf("初始化(initSql)length=%d\n",L.length);
	} 
	
	if(insertElem(&L,1,1)==1){
		printf("插入完成\n");
		printf("插入数据(insertElem)elem=%d\n",L.elem);
		printf("插入数据(insertElem)length=%d\n",L.length);
	}else{
		printf("插入失败");
	} 
	
	i = searchElem(&L,1);
	printf("查询数据(searchElem)1的位置item=%d\n",i);
	
	getElem(&L,1,&returnN);
	printf("获取数据(getElem)第1位的数据e=%d\n",returnN);
	
	deleteElem(&L,1);
	printf("删除数据(deleteElem)此时length = %d\n",L.length);

} 

总结

在写算法的时候,也有许多需要注意的地方。众所周知测试的小Bug在实际中可能会被无限放大。


比如:

1、每次要添加数据的时候,需要判断顺序表有没有满员,想指定插入的地方存不存在。增加之前,该元素要插入的位置后面的数据整体后移。

2、每次要删除数据的时候,需要判断顺序表有没有元素可以删,要指定删除的地方有没有元素。删除之后,该元素的后面所有元素整体前移。

这么看的话本来很难懂得东西就毕竟好理解了,因为是第一次使用C语言的指针和结构体,所以中间也踩了不少坑。

比如:

1、使用指针调用方法的时候,不能用 "."只能使用 ->(指向结构体的指针)。

2、定义方法 
int initSql(sqList *L);	*用来声明地址	
3、使用方法
initSql(sqList &L); 	&用来取地址
  • 2
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值