小楼一阁的数据结构学习笔记(二、顺序表)

距离上一篇学习笔记隔离了好久哈,因为上学期没有开数据结构的课程,自学的。这学期捡起来。

我想在大家看这篇博客的时候,已经对数据结构的一些最最基础的东西都了解,比如说什么是算法啦,什么链表之类的,其实数据结构就是一种种的结构,用来处理各种问题。

下面我介绍一下顺序表。

一、什么是顺序表

大家知道数组吗?数组就是一种非常简单的顺序表,但是数组有局限性,数组需要指定大小,而且数据会超出。。真忧伤= =,但是我们可以通过一种方法让数组变成要多大就有多大的东东,高档吧?

顺序表就是这种东西,他和数组一样,申请的是一块连续的内存(链表不是连续的内存,是分开的),所以说我们可以通过下标来确定顺序表中的元素位置和信息,顺序表可以理解为强大的数组,因为他就是用数组实现的一种东东。

二、顺序表整体构建

把我写的顺序表的整体法上来,然后再一段一段的分析,我想,长篇大论大家肯定看不进去,我紧握最大的努力让大家明白,大家一起拿下数据结!!!



首先讲一下顺序表:

       顺序表是有一个前驱,一个后继。

顺序表分别有四种基本操作以及很多其他的操作。因为四种基本操作掌握之后,拿下别的操作没有任何问题。

四种基本操作分别是:初始化,增加,插入,删除。

开始讲解:

        在可爱的C语言中,顺序表是由一个结构体来作为基础的,其中包括三项:

typedef struct list {
      Elemtype *elem;   //设置顺序表主体
      Elemtype length;  //用来控制顺序表长度
      Elemtype listsize;  //用来控制顺序表容量
}
容量和大小是不一样的。比如说我初始化一个有10个空间的数组elem,向数组中放入4个数据,那么数组的容量就是10,而长度是4。

初始化操作:

        因为顺序表是建立在结构体中的,那里只是一个定义而已哦,你得弄出一个真家伙来,那就是初始化操作,让顺序表真正的诞生。

在初始化之前,先在程序前面定义一个MORENUM和一个BASENUM 大小自己定义。一个是用来设置顺序表基础大小的,一个是用来扩增顺序表的,顺序表比数组的强大之处,就是没有大小的限制,那么每次不够了都要扩增一下,MORENUM就是用来扩增用的数。

void Initlist(LIST *L) {    
	L->elem = (int *)malloc(BASENUM * sizeof(int));  //首先给顺序表申请一段内存
	if(!L->elem) {      //错误排除  万一申请出错 报错
		printf("error");
		exit(0);
	}
	L->length = 0;     //设置一个顺序表长度的参数,用来动态申请用,因为没有数据所以是0
	L->listsize = BASENUM;   //设置基础大小,用来动态申请用
}
增加和插入操作(我合成为了一个):

      增加操作故名思议就是向顺序表中添加数据,因为这是智能的顺序表~~~所以不能直接向数组一样直接就赋值,需要考虑两个问题,第一插入数据的位置是否有数据,要是有的话那就必须将此位置的数据一次往后挪一个,然后空出来的位置放置新数据,这样就完成了插入操作。第二,还需要考虑一个问题就是我现在顺序表有10个空间,我想插入第11个数据,那么就必须扩增顺序表阿,因为咱们很智能,让他自己扩充。第三,插入操作不能乱插入,我有10个空间,你非要向20位置插入,可以插入,但是中间有空洞,这是不允许的,所以还得加个小判断,来判断位置是否合法。

下面是代码:

void cha(LIST *L,int i,int e) {    //顺序表插入操作
	int *p,*q;  //定义两根指针,用来挪数据用
	if (i < 1 || i > L->length + 1) {  //判断插入位置是否合法
		printf("error2");
		exit(0);
	}
	if(L->length >= L->listsize) {   //扩增表判断,如果长度大于容量了
		int *newbase;           //先弄一个新的指针
		newbase = (int *)realloc(L->elem,(L->listsize + MORENUM) * sizeof(int));
                //上面这句,把我们原来的表用realloc函数扩增,并且把结果给newbase指针
                if (!newbase) {  //仍然是错误判断
			printf("error3");
			exit(0);
		}
		L->elem = newbase;   //然后把我们的基础设置为新的newbase,这样不就扩大了吗
		L->listsize += MORENUM;    //既然扩大了,那么容量就变成新的了
	}
	i--;   //因为要插入的是第几个位置,数组是从0开始的哦,所以要减一
	p = &L->elem[i];    //让p指针指向要插入的位置
	for (q = &L->elem[L->length - 1]; q >= p; --q) {//这段放到后方解释,用来挪数据
                *(q + 1) = *q;
	}
	*p = e;   //挪完了数据是不是就有个空,数据放进去吧
	++L->length;    //然后让长度加一
}

下面解释一下刚才for循环:

        我们放进去数据是不是要弄一个空出来,那么这个循环就是这个作用,挪动数据我们这里从来往前挪,将最后一个数据向后挪一位,然后到数第二个挪到最后一个一次类推,

q = &L->elem[L->length - 1]
用来指向最后一个位置

q >= p
判断是否挪完,我们用p指针指向了空的位置,挪到这里就不能在挪了。

--q
顺序表中的数据地址是连续的,这是顺序表的特点之一,所以我们这里的操作是在地址上进行的,那么这句就是用来标志位置的,一个一个往后挪位置,因为从后往前,所以--q

删除操作:

        数列的删除操作同插入差不多,但是不用考虑表空间的扩增,用同样的for循环来

void elemDelete(LIST *L,int i,int e) {    //顺序表插入操作
	int *p,*q;
	if (i < 1 || i > L->length + 1) {
		printf("error2");
		exit(0);
	}
	i--;
	p = &L->elem[i];
	for (q = &L->elem[L->length - 1]; q > p; p++) {
		*p = *(p + 1);
	}
	--L->length;
}


首先通过一个例子来让大家整体理解顺序表

①输入一个单调递增有序数列,并且输入要输入的个数,然后输入一个数,插入到顺序表中,并且使插入后的顺序表仍然有序

上代码:

#include <stdio.h>
#include <stdlib.h>    //定义头文件,需要用到realloc函数
#define BASENUM 3      //定义顺序表基础大小,大楼不也得有个地基吗
#define MORENUM 10     //因为是不限长度的,每次不够了咱就申请,设置一个申请大小(设置成1不就是要多少给多少了吗)
typedef struct list {
	int *elem;
	int length;
	int listsize;
}LIST;     //必然是用结构体构成顺序表的
void shu(LIST *L) {     //输出函数(就像输出数组一样)
	int i;
	for (i = 0; i < L->length; i++) {
		printf("%d ",L->elem[i]);
	}
	printf("剩余量为%d\n",L->listsize - L->length);
}
void Initlist(LIST *L) {    //顺序表初始化
	L->elem = (int *)malloc(BASENUM * sizeof(int));   //稍后介绍realloc和malloc函数,非常重要滴!这里就是申请一段大小的内存,然后给顺序表作为基础大小
	if(!L->elem) {      //错误排除  万一申请出错 报错
		printf("error");
		exit(0);
	}
	L->length = 0;     //设置一个顺序表长度的参数,用来动态申请用
	L->listsize = BASENUM;   //设置基础大小,用来动态申请用
}
void cha(LIST *L,int i,int e) {    //顺序表插入操作
	int *p,*q;
	if (i < 1 || i > L->length + 1) {
		printf("error2");
		exit(0);
	}
	if(L->length >= L->listsize) {
		int *newbase;
		newbase = (int *)realloc(L->elem,(L->listsize + MORENUM) * sizeof(int));
		if (!newbase) {
			printf("error3");
			exit(0);
		}
		L->elem = newbase;
		L->listsize += MORENUM;
	}
	i--;
	p = &L->elem[i];
	for (q = &L->elem[L->length - 1]; q >= p; --q) {
		*(q + 1) = *q;
	}
	*p = e;
	++L->length;
}
void fre(LIST *L) {    //C语言用完了东西要知道施放,防止内存泄漏啊
	free(L->elem);
	L->elem = NULL;
	L->length = 0;
	L->listsize = 0;
}
int fang(LIST *L,int e) { //这是放进顺序表一个数使插入后的表仍然有序的操作
	int i;
	if (L->elem[0] > e) {
		cha(L,1,e);
		return 1;
	}
	if (L->elem[L->length - 1] < e) {
		cha(L,L->length + 1,e);
		return 1;
	}
	for (i = 0; i < L->length; i++) {
		if (L->elem[i] <= e && L->elem[i + 1] > e) {
			cha(L,i + 2,e);
			return 1;
		}
	}
}
int main (void) {   //主函数
	int i,j;
	int p,e;
	LIST L;
	Initlist(&L);
	printf("请输入要输入的个数:");
	scanf("%d",&j);
	printf("请输入有序的数列:");
	for (i = 1; i <= j; i++) {
		scanf("%d",&e);
		cha(&L,i,e);
	}
	shu(&L);
	printf("请输入要插入的数字:");
	scanf("%d",&p);
	fang(&L,p);
	shu(&L);
	fre(&L);
}

推荐大家看一遍代码注释了解一下大体思路在来看具体解法,思路清晰才能做好程序。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值