【数据结构】线性表

介绍线性表的定义与基本操作

目录

前言

正文

1、线性表的定义

2、线性表的基本操作

 3、顺序表

 4、顺序表的实现

1、顺序表的定义

2、顺序表的初始化

 3、为表中添加数据

4、 输出顺序表

5、插入数据 

6、删除数据 

7、增加顺序表最大长度 

5、完整代码

头文件.h

index.c 

 函数.c

总结


前言

        线性结构的特点是数据元素之间的关系是线性的,数据元素可以被看成排列在一条线上或一个环上。线性表是最简单的最常用的一种数据结构。值得注意的是数组在某种意义上也可被看作一种线性结构。


正文

1、线性表的定义

        线性表是n(n>=0)个数据元素组成的有限序列。

一般用L表示线性表记作:

        L=(a1,a2,a3,a4.....an)

        表中的元素可以是一个数、一个符号或是由多个数据项组成的复杂信息,但同一线性表中的元素必须属于同一个数据对象。例如:英文字母(A,B,C,D,E,F,G,H....).

       线性表的逻辑结构是通过元素之间的相邻关系来体现的。a1为起始节点an为终端节点,其中对任意一对相邻的节点ai和ai+1,ai被称为ai+1的直接前驱,ai+1被称为ai的直接后继(1<=i<=n-1)。线性表中元素的个数(n)称为该表的长度。长度为零(n=0)的表示空表

2、线性表的基本操作

        线性表是一种灵活的数据结构,可以在任意位置上进行插入和删除,其表长也根据不同的操作增加或缩短。对于线性表有以下几种常用的基本操作:

 3、顺序表

        线性表的顺序存储称为顺序表,它是由一组连读的存储单元依次存储线性表中的数据元素,从而使得逻辑上相邻的两个数据元素,物理位置上也相邻

        由于线性表中的所有数据元素属于同一种数据类型,所有每个元素所占的内存空间大小也相同。如下表,假设下标为0的内存地址为LOC(A),每个元素所占的空间大小为sizeof(ElemType),则下标为i-1的元素地址为:LOC(A)+(i-1)*sizeof(ElemType)

顺序表的特点:

  • 顺序表最主要的特点事随机存取,即通过首地址和元素序号可在时间o(1)内找到指定的元素 
  • 顺序表的存储密度高,每个节点只存储数据元素
  • 顺序表逻辑上相邻的元素物理上也相邻,所有插入和删除操作需要移动大量元素。

 4、顺序表的实现

1、顺序表的定义

1)静态顺序表,使用定长数组来存储元素

        缺陷:给小了不够用,给大了可能浪费,非常不实用

#define MaxSize 50  // 线性表的最大长度

typedef int sq_type; // 类型重命名,方便后续使用其他类型是修改

typedef struct{
	sq_type data[MaxSize]; // 定义定长数组
	sq_type size;  // 有效数据个数 
}Sqlist;

2)动态顺序表,根据长度进行开辟新的空间 

        动态顺序表可以根据我们的需要来设置默认以及增加空间

#define InitSize 20  // 定义线性表的最大长度

typedef int sq_type; // 类型重命名,方便后续使用其他类型是修改

typedef struct{
	sq_type* data; // 定义定长数组
	sq_type Maxsize; // 顺序表的最大长度
	sq_type size;  // 当前有效数据个数 
}Sqlist;

2、顺序表的初始化

        将定义顺序表中的成员初始化

void InitList(Sqlist* plist) {
	puts("正在初始化顺序表中");
	plist->data = (sq_type*)malloc(InitSize * sizeof(sq_type));  // 开辟一个大小为InitSize的内存空间并让data指向它
	plist->Maxsize = InitSize; // 为当前最大长度赋值为初始最大长度
	plist->size = 0; // 记录当前顺序表中有效值为零
	puts("初始化成功....");
}

 3、为表中添加数据

void add(Sqlist* plist) {
	puts("请输入数据(输入负数截至):");
	sq_type num;  // 元素值
	scanf("%d", &num);
	int i = 0;
    plist->size=0; // 重置有效值个数
	while (num >= 0) {
		if (plist->size < plist->Maxsize){ // 判断当前有效值是否小于当前最大长度
			plist->data[i++] = num; //为data添加输入的值
			plist->size += 1; // 添加成功后有效值加一
		}
		else {  // 当有效值>=最大长度时停止添加数据
			printf("当前以输入数据量%d,已达最大长度,如需增加长度请运行相应代码\n", plist->size);
			break;
		}
		printf("当前以输入数据量%d,还可输入%d个:\n", plist->size, plist->Maxsize - plist->size);
		scanf("%d", &num);  // 再次输入为添加下一个值做准备
	}
}

4、 输出顺序表

void PrintList(Sqlist* plist) {
	puts("以下为当前顺序表中的数据"); 
	for (int i = 0; i < plist->size;i++) { // 使用当前有效个数进行输出,因为下标从零开始所以小于有效个数即可 
		printf("%d\t", plist->data[i]);
		if ((i+1) % 10 == 0) {  // 判断当前输出元素个数是否为10或10的倍数,是则换行,方便查看数据
			puts("");
		}
	}
	puts("");
}

5、插入数据 

// 成功返回1,失败返回0
int ListInsert(Sqlist* plist) {
	// 检查是否达到当前那最大空间
	if (plist->size == plist->Maxsize) {
		puts("已达最大空间,请添加空间在尝试");
		return 0;
	}
	// 检查顺序表是否为空
	if (plist == NULL) {
		puts("顺序表为空!请先初始化顺序表");
		return 0;
	}
	// 输入需要插入的位置
	puts("请输入需要插入的位置(从零开始):");
	int i = -1;
	scanf("%d", &i);
	// 当指定的位置为负,或者超过当前顺序表长度则重新输入
	// 输入的i==plist->size时表示插入在最后
	while (i < 0 || i > plist->size) {
		puts("输入错误,请重新输入!");
		scanf("%d", &i);
	}
	puts("请输入需要插入的元素:");
	sq_type e;
	scanf("%d", &e);
    // 从后往前,将数据往后移一位,到需要插入的位置后,停止
	for(int j = plist->size-1;j>=i;j--){
		plist->data[j + 1] = plist->data[j];
	}
    // 将数据添加到指定位置
	plist->data[i] = e;
	plist->size += 1;   // 有效值加1
	return 1;
}

6、删除数据 

// 指定位置删除顺序表中的元素
// 删除指定位置上面的元素,并返回该元素
sq_type LisstDelete(Sqlist* plist) {
	// 判断顺序表是否为空
	if (plist == NULL) {
		puts("顺序表为空!请先初始化顺序表");
		return 0;
	}
	puts("请输入需要删除的元素的位置(从零开始):");
	int i;
	scanf("%d", &i);
    // 位置需要大于零,并且小于当前有效值,在这里设置一个限制防止输入错误
	while (i < 0 || i >= plist->size) {
		puts("输入位置错误,请重新输入!");
		scanf("%d",&i);
	}
    // 得到需要删除的位置后,将元素赋给result
	int result=plist->data[i];
    // 将删除的位置,后面的元素往前移动
	for (int j = i; j < plist->size; j++) {
		plist->data[j] = plist->data[j + 1];
	}
	plist->size--; // 删除之后有效值减1
	return result;  // 返回被删除的元素
}

7、增加顺序表最大长度 

// 增加顺序表的最大长度
void ListAddSize(Sqlist* plist) {
    // 定义指针来指向当前有效数据所在的空间
	sq_type *p = plist->data;
	printf("当前顺序表最大长度为:%d\n",plist->Maxsize);
	puts("请输入需要添加长度的个数:");
	int len;
	scanf("%d", &len);
    // 增加的长度需要大于零
	while (len < 0) {
		puts("输入错误请重新输入!");
		scanf("%d", &len);
	}
    // 重新为data开辟一个新的空间,空间大小为当前最大长度加需要增加的长度
	plist->data = (sq_type*)malloc(sizeof(sq_type) * (plist->Maxsize + len));
    // 将原来的数据赋值到新开辟的空间中
	for (int i = 0; i < plist->size; i++) {
		plist->data[i] = p[i];  // 注意p=plist->data 所以可以直接使用p来调用之前的数据
	}
    // 修改用于保存最大长度成员
	plist->Maxsize += len;
	free(p); // 释放原来的空间
	printf("添加成功!\n当前顺序表最大长度为:%d\n", plist->Maxsize);
}

5、完整代码

        本次顺序表使用分别使用了index.c、函数.c、头文件.h三个文件来实现,一下为每个文件中的代码

头文件.h

#pragma once // 防止头文件被二次调用

#include<stdio.h>   //perror, printf
#include<stdlib.h>  // malloc
#include<string.h>  // 导入字符串库 使用pust来写提示
#pragma warning(disable: 4996) // 禁用 scanf 相关警告

#define InitSize 12  // 定义线性表的最大长度

typedef int sq_type; // 类型重命名,方便后续使用其他类型是修改

typedef struct{
	sq_type* data; // 定义定长数组
	sq_type Maxsize; // 顺序表的最大长度
	sq_type size;  // 当前有效数据个数 
}Sqlist;

// 初始化顺序表
void InitList(Sqlist* plist);
// 增加数据
void add(Sqlist* plist);
// 输出顺序表
void PrintList(Sqlist* plist);
// 指定位置插入
int ListInsert(Sqlist* plist);
// 指定位置删除
sq_type LisstDelete(Sqlist* plist);
// 扩容  添加顺序表的最大长度
void ListAddSize(Sqlist* plist);

index.c 

#include "头文件.h"

int main() {
	Sqlist* head = (Sqlist*)malloc(sizeof(Sqlist));
	InitList(head);
	add(head);
	PrintList(head);
	int num=0;
	while(num>=0){
		puts("\n请选择您需要的功能(输入负数退出):");
		puts("1、输出顺序表");
		puts("2、输出顺序表的长度");
		puts("3、指定位置插入数据");
		puts("4、指定位置删除数据");
		puts("5、扩容:增加顺序表最大长度");
		puts("6、重新输入所有数据");
		scanf("%d", &num);
		switch (num) {
			case 1:PrintList(head); break;
			case 2:printf("当前顺序表的长度为:%d\n", head->size); break;
			case 3:
				if (ListInsert(head))
					puts("插入成功!");
				else
					puts("插入失败");
				break;
			case 4:printf("已删除指定位置的元素,该元素为:%d",LisstDelete(head)); break;
			case 5:ListAddSize(head); break;
			case 6:add(head); break;
			case -1: break;
			default:puts("选择出错啦,请重新选择!"); break;
		}
	}
	return 0;
}

 函数.c

#include"头文件.h"

void InitList(Sqlist* plist) {
	puts("正在初始化顺序表中");
	plist->data = (sq_type*)malloc(InitSize * sizeof(sq_type));
	plist->Maxsize = InitSize;
	plist->size = 0;
	puts("初始化成功....");
}

// 添加数据
void add(Sqlist* plist) {
	puts("请输入数据(输入负数截至):");
	sq_type num;
	scanf("%d", &num);
	int i = 0;
	plist->size=0;  // 重置有效值个数
	while (num >= 0) {
		if (plist->size < plist->Maxsize){
			plist->data[i++] = num;
			plist->size += 1;
		}
		else {
			printf("当前以输入数据量%d,已达最大长度,如需增加长度请运行相应代码\n", plist->size);
			break;
		}
		printf("当前以输入数据量%d,还可输入%d个:\n", plist->size, plist->Maxsize - plist->size);
		scanf("%d", &num);
	}
}

// 输出顺序表
void PrintList(Sqlist* plist) {
	puts("以下为当前顺序表中的数据");
	for (int i = 0; i < plist->size;i++) {
		printf("%d\t", plist->data[i]);
		if ((i+1) % 10 == 0) {
			puts("");
		}
	}
	puts("");
}

// 顺序表的插入
// 成功返回1,失败返回0
int ListInsert(Sqlist* plist) {
	// 检查是否达到当前那最大空间
	if (plist->size == plist->Maxsize) {
		puts("已达最大空间,请添加空间在尝试");
		return 0;
	}
	// 检查顺序表是否为空
	if (plist == NULL) {
		puts("顺序表为空!请先初始化顺序表");
		return 0;
	}
	// 输入需要插入的位置
	puts("请输入需要插入的位置(从零开始):");
	int i = -1;
	scanf("%d", &i);
	// 当指定的位置为负,或者超过当前顺序表长度则重新输入
	// 输入的i==plist->size时表示插入在最后
	while (i < 0 || i > plist->size) {
		puts("输入错误,请重新输入!");
		scanf("%d", &i);
	}
	puts("请输入需要插入的元素:");
	sq_type e;
	scanf("%d", &e);
	for(int j = plist->size-1;j>=i;j--){
		plist->data[j + 1] = plist->data[j];
	}
	plist->data[i] = e;
	plist->size += 1;
	return 1;
}

// 指定位置删除顺序表
// 删除指定位置上面的元素,并返回该元素
sq_type LisstDelete(Sqlist* plist) {
	// 判断顺序表是否为空
	if (plist == NULL) {
		puts("顺序表为空!请先初始化顺序表");
		return 0;
	}
	puts("请输入需要删除的元素的位置(从零开始):");
	int i;
	scanf("%d", &i);
	while (i < 0 || i >= plist->size) {
		puts("输入位置错误,请重新输入!");
		scanf("%d",&i);
	}
	int result=plist->data[i];
	for (int j = i; j < plist->size; j++) {
		plist->data[j] = plist->data[j + 1];
	}
	plist->size--;
	return result;
}

// 增加顺序表的最大长度
void ListAddSize(Sqlist* plist) {
	sq_type *p = plist->data;
	printf("当前顺序表最大长度为:%d\n",plist->Maxsize);
	puts("请输入需要添加长度的个数:");
	int len;
	scanf("%d", &len);
	while (len < 0) {
		puts("输入错误请重新输入!");
		scanf("%d", &len);
	}
	plist->data = (sq_type*)malloc(sizeof(sq_type) * (plist->Maxsize + len));
	for (int i = 0; i < plist->size; i++) {
		plist->data[i] = p[i];  // 注意p=plist->data 所以可以直接使用p来调用之前的数据
	}
	plist->Maxsize += len;
	free(p);
	printf("添加成功!\n当前顺序表最大长度为:%d\n", plist->Maxsize);
}

总结

        理解之后一点都不难嘛,和链表区别不大。

        欢迎指针!共同进步!

  • 27
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值