目录
一、线性表
概述: 线性表是具有相同 数据类型的的 有限序列(有次序)
-
元素之间是有顺序的,若干元素存在多个,则第一个元素无前驱,最后一个元素无后驱,其他元素都有一个前驱和后继。
如上图称 ai-1是ai的直接前驱元素,ai+1是ai的直接后继元素。线性表的元素个数n(n>=0)定义为线性表的长度,当n=0时,称为空表。在非空表中的每个数据都有一个确定的位置,称 i 为数据 ai 在线性表中的位序。
1.2 线性表的顺序结构
概述:顺序表 —— 用 顺序存储 的方式实现的线性表顺序存储。把 逻辑上相邻 的元素存储在 物理位置上也相邻 的存储单元中,元素之间的关系由存储单元的邻接关系来体现。线性表的顺序结构为数组,需要三个属性
-
存储空间:数组data
-
线性表的最大存储容量:数组长度maxsize
-
线性表的当前长度:length
#define MIXSIZE 30
#define LENTH 20
// 线性表的结构
struct line
{
int data[maxsize];
int length;
}
注意:数组长度是存储空间的总长度在分配后是不变的,线性表长度是线性表中数据元素的个数,随着线性表的插入删除操作进行变化的。
1.3 线性顺序表的基本操作
1.3.1 定义线性顺序表
//1 定义一个线性表
#define MIXSIZE 30
#define LENTH 20
typedef struct List
{
int m_data[MIXSIZE]; // 存储数据 MIXSIZE空间大小
int m_lenth; // 计算线性表的长度
}Sqlist;
1.3.2 给线性表插入数据
// 在线性表的 第 i 个位置插入 数据e
void ListInsert(Sqlist* List, int i, int e)
{
// 判断非法性
//1 当前线性表的长度大于等于 线性表总长度
//2 插入的位置 小于第一个元素的位置 或者 大于最后一个元素的后一位的后一位 位置
if (List->m_lenth >= MIXSIZE)
return 0;
if (i < 1 || i > List->m_lenth + 1)
return 0;
// 插入元素
//1 判断插入的位置 是不是在最后
//2 是在最后面直接追加插入 不是在最后 要从插入元素的位置 依次把后面的所有元素往后移一位 腾出位置后再插入
if (i <= List->m_lenth)
{
// 从最后一个元素位置开始 到要插入的位置 依次网后移一位
for (int j = List->m_lenth - 1; j >= i - 1; j--)
{
List->m_Age[j + 1] = List->m_Age[j];
}
}
//1 移出位置后直接在 位置插入元素
//2 更新元素的长度
List->m_Age[i - 1] = e;
List->m_lenth++;
}
1.3.3 删除线性表的数据
// 删除链表的一个元素
// 判断删除的合理性
//2 线性表为空 --- 非法
//3 位置不正确
// 删除第一个前一个 删除最后一个后一个 --- 非法
//4 删除 取出删除元素 把后面的元素往前移动一位
/***************************************
** 删除线性表的 第i 个元素 并用e 接收返回素
**
****************************************/
void LisrDelet(Sqlist* List, int i, int* e)
{
if (List->m_lenth == 0) // 线性表长度为0 即没有元素不能删除
return 0;
if (i == 0 || i >= List->m_lenth) // 删除的位置超出线性表长度 或者删除第0 个元素 非法
return 0;
*e = List->m_data[i - 1]; // 取出删除的元素
if (i < List->m_lenth) // 把元素全部前移一位
{
for (int k = i; k < List->m_lenth; ++k)
{
List->m_data[k - 1] = List->m_data[k];
}
}
List->m_lenth--; // 线性表长度减一
}
1.3.4 完整代码
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#define MIXSIZE 30
// 定义线性表
typedef struct List
{
int m_data[MIXSIZE];
unsigned int m_lenth;
}Sqlist;
// 在链表的 第 i 个位置插入 数据e
void ListInsert(Sqlist* List, int i, int e)
{
// 判断非法性
//1 当前链表的长度大于等于 链表总长度
//2 插入的位置 小于第一个元素的位置 或者 大于最后一个元素的后一位的后一位 位置
if (List->m_lenth >= MIXSIZE)
return 0;
if (i < 1 || i > List->m_lenth + 1)
return 0;
// 插入元素
//1 判断插入的位置 是不是在最后
//2 是在最后面直接追加插入 不是在最后 要从插入元素的位置 依次把后面的所有元素往后移一位 腾出位置后再插入
if (i <= List->m_lenth)
{
// 从最后一个元素位置开始 到要插入的位置 依次网后移一位
for (int j = List->m_lenth - 1; j >= i - 1; j--)
{
List->m_data[j + 1] = List->m_data[j];
}
}
//1 移出位置后直接在 位置插入元素
//2 更新元素的长度
List->m_data[i - 1] = e;
List->m_lenth++;
}
// 删除链表的一个元素
// 判断删除的合理性
//2 线性表为空 --- 非法
//3 位置不正确
// 删除第一个前一个 删除最后一个后一个 --- 非法
//4 删除 取出删除元素 把后面的元素往前移动一位
void LisrDelet(Sqlist* List, int i, int* e)
{
if (List->m_lenth == 0)
return 0;
if (i == 0 || i >= List->m_lenth)
return 0;
// 取出删除的元素
*e = List->m_data[i - 1];
if (i < List->m_lenth)
{
for (int k = i; k < List->m_lenth; ++k)
{
List->m_data[k - 1] = List->m_data[k];
}
}
List->m_lenth--;
}
int main(void)
{
// 定义链表
Sqlist Age;
Age.m_lenth = 20;
// 给链表添加数据
for (int i = 0; i < Age.m_lenth; ++i)
{
Age.m_data[i] = i * 2;
}
// 打印为插入数据前的链表
for (int t = 0; t < Age.m_lenth; ++t)
{
printf("%d ", Age.m_data[t]);
}
// 在线性表第3个位置插入元素
ListInsert(&Age, 3, 666);
// 打印插入元素后的链表
printf("\n----------------在链表的第3个元素位置插入 666---------------------\n");
for (int t = 0; t < Age.m_lenth; ++t)
{
printf("%d ", Age.m_data[t]);
}
// 删除线性表的第 7个元素
int e = 0;
LisrDelet(&Age, 7, &e);
// 打印删除元素后的线性表
printf("\n----------------删除线性表的第7个元素后的线性表---------------------\n");
for (int t = 0; t < Age.m_lenth; ++t)
{
printf("%d ", Age.m_data[t]);
}
printf("\n删除的元素e = %d\n ", e);
return 0;
}
结果
0 2 4 6 8 10 12 14 16 18 20 22 24 26 28 30 32 34 36 38
----------------在链表的第3个元素位置插入 666---------------------
0 2 666 4 6 8 10 12 14 16 18 20 22 24 26 28 30 32 34 36 38
----------------删除线性表的第7个元素后的线性表---------------------
0 2 666 4 6 8 12 14 16 18 20 22 24 26 28 30 32 34 36 38
删除的元素e = 10
总结: 对线性顺序表的操作就是对数组的操作,在线性表中间每添加一个数据或者删除一个数据,都要移动其余元素。