数据结构:线性表(顺序表的实现)

线性表之顺序存储---顺序表

逻辑结构: 线性结构 元素和元素之间 存在1:1
    内存空间的天然连续性  逻辑上连续性  映射   顺序表 

逻辑结构和行为 (抽象数据类型)

线性表:
    存储行为
        顺序存储
    访问的接口
     <1> 初始化的动作
     <2> 获取某个位置元素的动作
            传入pos,直接访问索引为pos - 1位置的值 ,某个位置找到元素的效率非常高,时间复杂度为O(1)
     <3>查找某个元素的位置,时间复杂度为O(n)
     <4>插入某个元素在表的某个位置上
            要在pos插入元素     [pos ... n] 都往后移动一位 ,内部索引[pos-1...n-1]都往后移动一位,效率不高,时间复杂度为O(n)
     <5>删除...
            要把pos位置的元素删除  [pos+1 ... n] 往前移动一位,对程序来说,索引为[pos...n-1] 的值都要往前移动一位,效率不高,时间复杂度为O(n)
     <6>更新...
            传入pos,要更改pos位置的值,只需更改索引为pos-1位置的值, 效率非常高,时间复杂度为O(1)

这些过程中需要注意内部的索引是从0开始的,[0,1,2,...n-1]

而对外接口是从1开始的,[1,2,...n]


三、动态顺序表的设计与实现

静态顺序表:
    数组来存储表里的元素
        int data[5]; 一旦申请空间,空间个数确定,不能变化,经常会空间不够,不建议使用。

动态顺序表:

    动态空间来存储表里的元素  C语言用指针来实现,int *elem用指针来指向动态区

空间不够时,我们可以申请新的空间。

 

 

 如上图所示,表中只有元素1和2,elem[100]出现越界,为避免此情况,需要长度len

除此之外,len可能比目前的容量还大,需要扩容,所以我们需要知道容量capacity

故要想维护一个动态顺序表,我们需要有这三个元素。

 代码:

sqList.h


#ifndef SQLIST_H
#define SQLIST_H
/*
 * 动态顺序表,使用顺序存储,数据容量动态增加
 * 外部按照[1,...,n]的方式进行访问
 * 内部使用C语言实现,索引从0开始
 */
typedef int Element;//这个元素不一定是int,用typedef重命名,以后假如存的不是int,改一下就可以,这样就不用通篇都要改

//动态顺序表必要的三个元素是一个整体,整体用struct结构体,最好也用typedef重命名一下
typedef struct {
	Element *elem;      //顺序表元素空间首地址
	int len;            //记录顺序表的元素个数
	int capacity;       //记录顺序表的容量
}SqList;

//第一件事情初始化,先产生这个表
SqList *creatSqList(int n);         //产生容量为n个元素的顺序表

void releaseSqList(SqList *seq);    //释放这个顺序表

//获取顺序表中某个位置上元素的值
//在哪个seq表中获取,返回是否找到(有可能越界没找到,故函数为int类型,返回-1出错,返回0则找到),很显然返回这个值,值用指针反向更新
int getSqList(SqList *seq,int pos,Element *ele);

//查找顺序表中某个元素的位置
//在哪个seq表中找哪个元素ele(这里的ele不用更新,故不用指针)
int locateSqList(SqList *seq,Element ele);

//向顺序表指定位置上插入元素
int insertSqList(SqList *seq,int pos,Element ele);

//显示顺序表里的元素
void showSqList(SqList *seq);

//从顺序表中指定位置处删除元素
//从哪个seq表中删除某个位置pos的元素
int deleteSqList(SqList *seq,int pos);
#endif //SQLIST_H

sqList.c

#include <stdlib.h>
#include <stdio.h>
#include "sqList.h"

SqList *creatSqList(int n){
	SqList *seq = (SqList *)malloc(sizeof(SqList));//申请空间,为了安全,前面加强制类型转换
	// 判断申请是否成功
	if(seq == NULL){
		printf("malloc error\n");
		return NULL;
	}
//初始化顺序表里的每个元素
	seq->elem = (Element *)malloc(sizeof(Element)*n);//申请n个元素的空间
	//初始化,给每个元素赋值0
	for(int i =0;i<n;++i){
		seq->elem[i]=0;
	}
	seq->len = 0;//长度最开始为0
	seq->capacity = n;//容量为n
	return seq;
}
//先释放里面的,再释放外面的空间
void releaseSqList(SqList *seq){
	//首先判断用户传来的seq是非空的
	if(seq){
		//如果不空,判断不空的seq里的元素是否申请
		if(seq->elem){
			free(seq->elem);//释放元素
		}
		free(seq);//释放表
	}
}

/*[1,2,...,seq->len] pos的用户访问范围,对外
 *
 */
int getSqList(SqList *seq,int pos,Element *ele){
	//pos必须在1到len之间,否则pos位置无效,返回-1
	if(pos < 1 || pos > seq->len){
		printf("pos invalid!\n");
		return -1;
	}
	*ele = seq->elem[pos-1];//反向更新
	return 0;//成功返回0
}

//找元素,顺序表天然就是一个数组,for循环遍历
int locateSqList(SqList *seq,Element ele){
	for(int i=0;i<seq->len;++i){
		if(seq->elem[i]==ele){
			return i+1;//找到了,返回位置
		}
	}
	return 0;//没找到
}

/*插入操作:
 *外部范围:[1,...seq->len]
 * 插入行为:可以在表的最后插入,范围是[1,...seq->len+1]
 */
int insertSqList(SqList *seq,int pos,Element ele){
	//判断插入范围是否正确
	if(pos < 1 || pos > seq->len+1){
		printf("pos invalid!\n");
		return -1;
	}
	//判断容量是否满足
	if(seq->len +1 > seq->capacity){ //容量越界,就扩容
		printf("enlarge!\n");
		//扩容要申请一个新空间,临时申请一个tmp,一般扩到原来的2倍
		Element *tmp = (Element *)malloc(sizeof(Element) * seq->capacity * 2);
		//判断扩容是否成功
		if(tmp == NULL){
			printf("malloc error\n");
			return -1;
		}
		//成功扩容之后
		//把老空间的值拷贝给新空间
		for(int i = 0;i < seq->len;++i){
			tmp[i] = seq->elem[i];
		}
		seq->capacity = seq->capacity * 2;//容量更新
		free(seq->elem);//释放掉原来的老元素
		seq->elem = tmp;//指针指向新空间
	}
	//将pos位置后面的元素向后移一位,从seq->len逐步靠近pos的位置(从最后一个元素后移,往前操作,直到pos)
	for(int i = seq->len -1;i >= pos-1;--i){
		seq->elem[i+1] = seq->elem[i];//后移一位
	}
	seq->elem[pos-1]=ele;//插入新元素ele
	seq->len++;//更新表长
	return 0;
}

//显示seq就是一个遍历
void showSqList(SqList *seq){
	for(int i=0;i < seq->len;++i){
		printf("%d\t",seq->elem[i]);
	}
	printf("\n");
}

int deleteSqList(SqList *seq,int pos){
	if(pos < 1 || pos > seq->len){
		printf("pos invalid!\n");
		return -1;
	}
	//从pos+1位置到最后的位置处,向前赋值
	for(int i = pos; i < seq->len; ++i){
		seq->elem[i-1] = seq->elem[i];//将后一个位置的元素前移
	}
	seq->len--;//更新表长
	return 0;
}

main.c

#include <stdio.h>
#include "sqList.h"

int main(){
	int n = 5;
	//生成一个顺序表
	SqList *sqList = creatSqList(n);
	//操作这个顺序表
	for(int i = 0; i < n; ++i){
		insertSqList(sqList,i+1,i+100);

	}
	showSqList(sqList);
	insertSqList(sqList,3,300);
	showSqList(sqList);
	insertSqList(sqList,9,1000);
	showSqList(sqList);
	printf("--------------------\n");
	deleteSqList(sqList,4);
	showSqList(sqList);
	releaseSqList(sqList);
	return 0;
}

在CLion上的运行结果,如下图:

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值