考研二战_数据结构_day2_顺序表

目录

前言

一、顺序表的定义

二、顺序表的基本操作

1、数据表的实现方式——静态分配与动态分配

        1、静态分配

        2、动态分配

        3、小结

2、插入、删除

        1、插入

        2、删除

        3、小结

3、查找

        1、按位查找

        2、按值查找

        3、小结

4、修改

        1、按位

        2、按值

        3、小结

总结


前言

        以前用c语言,都是直接安装devc++,昨天突发奇想,想用vscode来配置c语言环境。

        结果按照教程到最后,发现报错了,于是我又重新找了几个教程。结果每次到测试的时候都会出现调用失败之类的问题,所以我还是老老实实地下了一个devc++。


一、顺序表的定义

        顺序表是具有相同数据类型的n(n≥0)个数据元素有限序列,其中n为表长,当n=0时顺序表是一个空表。若用L命名顺序表,则其一般表示为:

L = {(a_{1}, a_{2}, a_{3}, ..., a_{i}, a_{i+1}, ..., a_{n})}

        其中,a_{i} 中的 i 表示位序(从1开始);a_{1} 是表头元素,无前驱;a_{n} 是表尾元素,无后继。

         

二、顺序表的基本操作

        顺序表是一种数据结构,通用操作有——创销增删改查,有时也可加入判空、判长、判满、打印以及一些其他功能。

1、数据表的实现方式——静态分配与动态分配

        1、静态分配

        静态分配,数组的长度不可变,所以需要定义一个Maxsize来表示数组的最大长度。

        我觉得一个数组本身就可以看作是一个顺序表,所以length这个结构变量是否是可有可无。但是我又转念一想,加上了这个变量,好像对于顺序来说也不是什么坏事,而且还能使结构体更加完整,看上去也更加好看。

        以下是静态分配的实现方式。该顺序表被我命名为SqList,而ElemType则是默认使用int数据类型。

#define Maxsize 10  //数组最大长度
typedef int Elemtype;

typedef struct {
	Elemtype data[Maxsize];
	int length;
}SqList;

        2、动态分配

        动态分配,与静态分配有所不同的是,它的长度是可变的。因此需要对静态分配进行一定的修改。比如需要定义InitialSize用于表示顺序表初始长度。

        最重要的一点,写函数的时候注意使用&地址符来对原顺序表进行更改。不然内存空间中会有顺序表L与顺序表List。

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

#define InitialSize 10  //数组初始长度 
typedef int ElemType;

typedef struct {
	ElemType *data;
	int Maxsize;
	int length;
}SqList;

//初始化 
void InitList(SqList &L){
	L.data = (ElemType*)malloc(InitialSize*sizeof(ElemType));
	L.Maxsize = InitialSize;
	L.length = 0;
}

//增加顺序表长度
void IncreaseSize(SqList &L, int len){
	ElemType *p = L.data;  //先将L的数据存起来 
	L.data = (ElemType*)malloc((L.Maxsize + len)*sizeof(ElemType));  //再为L分配新空间 
	for(int i = 0; i<L.length; i++){
		L.data[i] = p[i];  //转移数据 
	}
	L.Maxsize += len;  //L的最大长度进行变更 
	free(p);  //释放原存储空间 
}

int main() {
	SqList list;
	InitList(list);
	IncreaseSize(list, 5);
	return 0;
}

        3、小结

        顺序表具有随机存储的特点,能在O(1)时间复杂度内找到位序为 i 的元素,而且存储密度大。但是缺点也很明显,扩容(主要是转移数据费时)、插入、删除都很不方便。

2、插入、删除

        顺序表的插入与删除十分麻烦,需要移动数组中的元素,开销很大。下面以动态分配时的情况为例。

        1、插入

//插入,在L中的位序为i的位置插入元素elem 
void Insert(SqList &L, int i, ElemType elem) {
	for(int j = L.length; j>=i; j--){
		L.data[j] = L.data[j-1];  //将数据元素后移一位
	} 
	L.data[i-1] = elem;  //插入元素
	L.length++;  //长度+1
} 

        以上是插入的一般思路,但是考虑到代码的健壮性,还需要考虑一些边界情况。

//插入,在L中的位序为i的位置插入元素elem 
bool Insert(SqList &L, int i, ElemType elem) {
	if(i<0 || i>length + 1) return false;   //i值超边界,插入失败 
	if(L.lenth >= L.Maxsize) return false;  //线性表已满,插入失败 
	for(int j = L.length; j>=i; j--) {
		L.data[j] = L.data[j-1];
	} 
	L.data[i-1] = elem;
	L.length++;
	return true;  //插入成功 
} 

        2、删除

//删除,删除在L中的位序为i的元素 
void Delete(SqList &L, int i) {
	for(int j = i; j<L.length; j++) {
		L.data[j-1] = L.data[j];  //将数据元素后移一位
	} 
	L.length--;  //长度-1
} 

        这是最基本的删除方法,除此以外,还可以考虑边界情况;或者也可以增加功能获取被删除的元素。

//删除,删除在L中的位序为i的元素
bool Delete(SqList &L, int i, ElemType &elem) {
	if(i<0 || i>L.length) return false;   //i值超边界,删除失败
	elem = L.data[i-1];
	for(int j = i; j<L.length; j++) {
		L.data[j-1] = L.data[j];  //将数据元素后移一位
	}
	L.length--;  //长度-1
	return true;
}

         以下是测试

int main() {
	SqList list;
	InitList(list);
	IncreaseSize(list, 5);
	for(int i = 0; i<5; i++) {
		ElemType temp = rand() % 10 + 1;  //生成一个1~10的数
		if(Insert(list, i+1, temp)) {
			printf("数字%d插入成功,list长度为%d!\n", temp, list.length);
		} else {
			printf("插入失败!\n");
		}
	}

    //打印结果,观察是否一致
	for(int i = 0; i<list.length; i++) {
		printf("%d ", list.data[i]);
	}
	puts("");

	ElemType elem = -1;
	if(Delete(list, 2, elem)) {  //删除位序为2的元素,并用elem来获取
		printf("删除成功,已删除数字%d\n", elem);
	} else {
		printf("删除失败!\n");
	}

	return 0;
}

        3、小结

        虽说增删在最好的情况下时间复杂度就只有O(1),但是在最差的情况下,其时间复杂度有O(n)

3、查找

        1、按位查找

        顾名思义,就是查找线性表L中位序为 i 的值

//按位查找,查找L中位序为i的元素的值,并获取该值
bool SearchByOrder(SqList L, int i, ElemType &result) {
	if(i<1 || i>L.length) return false;  //i值超边界,查找失败
	result = L.data[i-1];

	return true;
}

        2、按值查找

//按值查找,找到第一个就返回其位序
bool SearchByElem(SqList L, int &order, ElemType elem) {
	for(int i = 0; i<L.length; i++) {
		if(L.data[i] == elem) {
			order = i+1;
			return true;
		}
	}
	return false;
}

        3、小结

        由于查找过程中,不需要对原线性表进行操作,因此在传递参数时不需要加&

    ElemType result = -1;
	if(SearchByOrder(list, 3, result)) {  //查找位序为3的元素
		printf("查找成功,目标元素为%d\n", result);
	} else {
		printf("查找失败!\n");
	}

	int order = -1;
	if(SearchByElem(list, order, 5)) {  //查找第一个元素为5的位序
		printf("查找成功,目标元素位序为%d\n", order);
	} else {
		printf("查找失败!\n");
	}

         按位查找时间复杂度为O(1),按值查找时间复杂度为O(n)

4、修改

        1、按位修改

//按位修改,修改L中位序为i的元素的值为elem
bool UpdateByOrder(SqList &L, int i, ElemType elem) {
	if(i<1 || i>L.length) return false;  //i值超边界,修改失败
	L.data[i-1] = elem;
	return true;
}

        2、按值修改

//按值修改,修改L中元素的值为elem的元素的值为change
bool UpdateByElem(SqList &L, ElemType elem, ElemType change) {
	for(int i = 0; i<L.length; i++) {
		if(L.data[i] == elem) L.data[i] = change;
	}
	return true;
}

        3、小结

	if(UpdateByOrder(list, 2, 5)) {  //修改位序为2的元素为5
		printf("修改成功!\n");
	} else {
		printf("修改失败!\n");
	}

	if(UpdateByElem(list, 5, 11)) {  //修改元素为5的元素为11
		printf("修改成功!\n");
	} else {
		printf("修改失败!\n");
	}

 

         修改也算是比较简单的,按位时间复杂度为O(1),按值时间复杂度为O(n)


总结

        顺序表的实现还算比较简单。今天复习内容中最需要注意的是&的引用。

        还有,因为ElemType默认为int数据类型,所以我写代码的时候一直用的是ElemType,在打印结果时也是用的%d格式。而且为了保持前后文风格一致,可能看上去会有点冗长。

总览一下

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

#define InitialSize 10  //数组初始长度 
typedef int ElemType;

typedef struct {
	ElemType *data;
	int Maxsize;
	int length;
} SqList;

//初始化
void InitList(SqList &L) {
	L.data = (ElemType*)malloc(InitialSize*sizeof(ElemType));
	L.Maxsize = InitialSize;
	L.length = 0;
}

//增加线性表长度
void IncreaseSize(SqList &L, int len) {
	ElemType *p = L.data;  //先将L的数据存起来
	L.data = (ElemType*)malloc((L.Maxsize + len)*sizeof(ElemType));  //再为L分配新空间
	for(int i = 0; i<L.length; i++) {
		L.data[i] = p[i];  //转移数据
	}
	L.Maxsize += len;  //L的最大长度进行变更
	free(p);  //释放原存储空间
}

//插入,在L中的位序为i的位置插入元素elem
bool Insert(SqList &L, int i, ElemType elem) {
	if(i<1 || i>L.length + 1) return false;  //i值超边界,插入失败
	if(L.length >= L.Maxsize) return false;  //线性表已满,插入失败
	for(int j = L.length; j>=i; j--) {
		L.data[j] = L.data[j-1];  //向后移动1位
	}
	L.data[i-1] = elem;
	L.length++;

	return true;  //插入成功
}

//删除,删除在L中的位序为i的元素
bool Delete(SqList &L, int i, ElemType &elem) {
	if(i<1 || i>L.length) return false;   //i值超边界,删除失败
	elem = L.data[i-1];
	for(int j = i; j<L.length; j++) {
		L.data[j-1] = L.data[j];  //将数据元素后移一位
	}
	L.length--;  //长度-1
	return true;
}

//按位查找,查找L中位序为i的元素的值,并获取该值
bool SearchByOrder(SqList L, int i, ElemType &result) {
	if(i<1 || i>L.length) return false;  //i值超边界,查找失败
	result = L.data[i-1];

	return true;
}

//按值查找,找到第一个就返回其位序
bool SearchByElem(SqList L, int &order, ElemType elem) {
	for(int i = 0; i<L.length; i++) {
		if(L.data[i] == elem) {
			order = i+1;
			return true;
		}
	}
	return false;
}

//按位修改,修改L中位序为i的元素的值为elem
bool UpdateByOrder(SqList &L, int i, ElemType elem) {
	if(i<1 || i>L.length) return false;  //i值超边界,修改失败
	L.data[i-1] = elem;
	return true;
}

//按值修改,修改L中元素的值为elem的元素的值为change
bool UpdateByElem(SqList &L, ElemType elem, ElemType change) {
	for(int i = 0; i<L.length; i++) {
		if(L.data[i] == elem) L.data[i] = change;
	}
	return true;
}


int main() {
	SqList list;
	InitList(list);
	IncreaseSize(list, 5);
	for(int i = 0; i<6; i++) {
		ElemType temp = rand() % 10 + 1;  //生成一个1~10的数
		if(Insert(list, i+1, temp)) {
			printf("数字%d插入成功,list长度为%d!\n", temp, list.length);
		} else {
			printf("插入失败!\n");
		}
	}

	for(int i = 0; i<list.length; i++) {
		printf("%d ", list.data[i]);
	}
	puts("");

	ElemType result = -1;
	if(SearchByOrder(list, 3, result)) {
		printf("查找成功,目标元素为%d\n", result);
	} else {
		printf("查找失败!\n");
	}

	int order = -1;
	if(SearchByElem(list, order, 5)) {
		printf("查找成功,目标元素位序为%d\n", order);
	} else {
		printf("查找失败!\n");
	}

	if(UpdateByOrder(list, 2, 5)) {
		printf("修改成功!\n");
	} else {
		printf("修改失败!\n");
	}
	for(int i = 0; i<list.length; i++) {
		printf("%d ", list.data[i]);
	}
	puts("");

	if(UpdateByElem(list, 5, 11)) {
		printf("修改成功!\n");
	} else {
		printf("修改失败!\n");
	}
	for(int i = 0; i<list.length; i++) {
		printf("%d ", list.data[i]);
	}
	puts("");

	ElemType e = -1;
	if(Delete(list, 2, e)) {
		printf("删除成功,已删除数字%d\n", e);
	} else {
		printf("删除失败!\n");
	}

	return 0;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值