线性表
定义与特点
由n(n>=0)个数据特性相同的元素构成的有限序列,称为线性表。
线性表是n个数据元素的有限序列,其中n个数据是相同数据类型的。
线性表中元素个数n(n>=0)定义为线性表的长度,当n=0时称之为空表。
对于非空的线性表或线性结构,其特点是:
- 存在唯一的一个被称作“第一个”的元素;
- 存在唯一的一个被称作“最后一个”的元素;
- 除第一个元素外,结构中的每个元素均只有一个前驱;
- 除最后一个元素外,结构中的每个元素均只有一个后继。
案例引入:图书信息管理系统
| ISBN | 书名 | 定价 |
|---|---|---|
| 9787302257616 | 计算机基础 | 32 |
| 9787302256513 | 程序设计基础 | 46 |
| 9787302202816 | 数据库技术与应用 | 39 |
- 查找:根据指定的ISBN或书名查找相应图书的有关信息,并返回该图书在文件中的位置序号。
- 插入:插入一条新的图书信息。
- 删除:删除一条图书信息。
- 修改:根据指定的ISBN,修改该图书的价格。
- 排序:将图书按照价格由低到高进行排序。
- 计数:统计文件中的图书数量。
顺序表
线性表的 顺序表示 是指用 连续的物理存储空间 存储元素,即「顺序表」—— 元素的逻辑顺序与物理存储顺序完全一致,底层依赖数组实现。
存储结构
#define MAX_SIZE 100 //顺序表可能达到的最大长度
typedef int ElemType;
typedef struct {
ElemType elem[MAX_SIZE]; // 存储元素的数组
int length; // 当前元素个数(有效长度)
} SeqList; //顺序表的结构类型为SeqList
顺序表初始化
void InitSeqList(SeqList* L) {
if (L == NULL) return;
L->length = 0; // 初始无元素
}
完整代码演示:
#include<stdio.h>
#include<stdlib.h>
#define MAX_SIZE 100
typedef int ElemType;
typedef struct {
ElemType elem[MAX_SIZE]; // 存储元素的数组
int length; // 当前元素个数(有效长度)
} SeqList;
void InitSeqList(SeqList* L) {
if (L == NULL) return;
L->length = 0; // 初始无元素
}
int main()
{
//声明一个顺序表并初始化
SeqList list;
InitSeqList(&list);
printf("初始化成功,目前长度占用%d\n", list.length);
printf("目前占用内存%zu字节\n", sizeof(list.elem));
return 0;
}
运行结果:
初始化成功,目前长度占用0
目前占用内存400字节
在尾部添加元素
int appendElem(SeqList* L, ElemType e)
{
if (L->length >= MAX_SIZE) {
printf("顺序表已满\n");
return 0;
}
L->elem[L->length] = e;
L->length++;
return 1;
}
遍历
void listElemp(SeqList* L)
{
for (int i = 0; i < L->length; i++)
{
printf("%d ", L->elem[i]);
}
printf("\n");
}
添加元素+遍历的完整代码:
#include<stdio.h>
#include<stdlib.h>
#define MAX_SIZE 100
typedef int ElemType;
typedef struct {
ElemType elem[MAX_SIZE]; // 存储元素的数组
int length; // 当前元素个数(有效长度)
} SeqList;
void InitSeqList(SeqList* L) {
if (L == NULL) return;
L->length = 0; // 初始无元素
}
int appendElem(SeqList* L, ElemType e)
{
if (L->length >= MAX_SIZE) {
printf("顺序表已满\n");
return 0;
}
L->elem[L->length] = e;
L->length++;
return 1;
}
void listElemp(SeqList* L)
{
for (int i = 0; i < L->length; i++)
{
printf("%d ", L->elem[i]);
}
printf("\n");
}
int main()
{
//声明一个顺序表并初始化
SeqList list;
InitSeqList(&list);
printf("初始化成功,目前长度占用%d\n", list.length);
printf("目前占用内存%zu字节\n", sizeof(list.elem));
appendElem(&list, 88);
appendElem(&list, 56);
appendElem(&list, 34);
appendElem(&list, 62);
appendElem(&list, 45);
listElemp(&list);
return 0;
}
运行结果:
初始化成功,目前长度占用0
目前占用内存400字节
88 56 34 62 45
插入元素
// 在pos位置插入元素e (pos范围:0 ~ L->length)
int insertElem(SeqList* L, int pos, ElemType e)
{
if (pos <= L->length)
{
// 从后往前移动元素(避免覆盖)
for (int i = L->length - 1; i >= pos - 1; i--)//数组下标:pos - 1
{
L->elem[i + 1] = L->elem[i];
}
// 插入新元素
L->elem[pos - 1] = e;
L->length++;
}
return 1;
}
插入元素的完整代码:
#include<stdio.h>
#include<stdlib.h>
#define MAX_SIZE 100
typedef int ElemType;
typedef struct {
ElemType elem[MAX_SIZE]; // 存储元素的数组
int length; // 当前元素个数(有效长度)
} SeqList;
//初始化
void InitSeqList(SeqList* L) {
if (L == NULL) return;
L->length = 0; // 初始无元素
}
//添加数据
int appendElem(SeqList* L, ElemType e)
{
if (L->length >= MAX_SIZE) {
printf("顺序表已满\n");
return 0;
}
L->elem[L->length] = e;
L->length++;
return 1;
}
//遍历
void listElemp(SeqList* L)
{
for (int i = 0; i < L->length; i++)
{
printf("%d ", L->elem[i]);
}
printf("\n");
}
int insertElem(SeqList* L, int pos, ElemType e)
{
if (L->length >= MAX_SIZE)
{
printf("表已经满了\n");
return 0;
}
if (pos<1 || pos > L->length)
{
printf("插入位置错误\n");
return 0;
}
if (pos <= L->length)
{
for (int i = L->length - 1; i >= pos - 1; i--)
{
L->elem[i + 1] = L->elem[i];
}
L->elem[pos - 1] = e;
L->length++;
}
return 1;
}
int main()
{
//声明一个顺序表并初始化
SeqList list;
InitSeqList(&list);
printf("初始化成功,目前长度占用%d\n", list.length);
printf("目前占用内存%zu字节\n", sizeof(list.elem));
//添加元素
appendElem(&list, 88);
appendElem(&list, 56);
appendElem(&list, 34);
appendElem(&list, 62);
appendElem(&list, 45);
printf("原序列:");
listElemp(&list);
//插入
insertElem(&list, 2, 24);
printf("插入新元素后:");
listElemp(&list);
return 0;
}
运行结果:
顺序表插入数据的最好时间复杂度是?O(1) ——— 插入到最后的位置
顺序表插入数据的最坏时间复杂度是?O(n) ——— 插入到第一个位置
删除元素
int delectElem(SeqList* L, int pos, ElemType *e)
{
//保存删除的元素
*e = L->elem[pos - 1];
if (pos < L->length)
{
for (int i = pos; i < L->length; i++)
{
L->elem[i - 1] = L->elem[i];
}
}
L->length--;
return 1;
}
#include<stdio.h>
#include<stdlib.h>
#define MAX_SIZE 100
typedef int ElemType;
typedef struct {
ElemType elem[MAX_SIZE]; // 存储元素的数组
int length; // 当前元素个数(有效长度)
} SeqList;
//初始化
void InitSeqList(SeqList* L) {
if (L == NULL) return;
L->length = 0; // 初始无元素
}
//添加数据
int appendElem(SeqList* L, ElemType e)
{
if (L->length >= MAX_SIZE) {
printf("顺序表已满\n");
return 0;
}
L->elem[L->length] = e;
L->length++;
return 1;
}
//遍历
void listElemp(SeqList* L)
{
for (int i = 0; i < L->length; i++)
{
printf("%d ", L->elem[i]);
}
printf("\n");
}
//删除数据
int delectElem(SeqList* L, int pos, ElemType *e)
{
if (L == NULL || pos < 0 || pos >= L->length)
{
printf("删除失败:顺序表为空或参数非法\n");
return 0;
}
//保存删除的元素
*e = L->elem[pos - 1];
if (pos < L->length)
{
for (int i = pos; i < L->length; i++)
{
L->elem[i - 1] = L->elem[i];
}
}
L->length--;
return 1;
}
int main()
{
//声明一个顺序表并初始化
SeqList list;
InitSeqList(&list);
printf("初始化成功,目前长度占用%d\n", list.length);
printf("目前占用内存%zu字节\n", sizeof(list.elem));
//添加元素
appendElem(&list, 88);
appendElem(&list, 56);
appendElem(&list, 34);
appendElem(&list, 62);
appendElem(&list, 45);
printf("原序列:");
listElemp(&list);
//删除
ElemType delect;
delectElem(&list, 3, &delect);
printf("删除元素后:");
listElemp(&list);
return 0;
}
运行结果:
查找
int findElem(SeqList* L, ElemType e)
{
for (int i = 0; i < L->length; i++)
{
if (L->elem[i] == e)
{
return i + 1;
}
}
return 0;
}
完整代码:
#include<stdio.h>
#include<stdlib.h>
#define MAX_SIZE 100
typedef int ElemType;
typedef struct {
ElemType elem[MAX_SIZE]; // 存储元素的数组
int length; // 当前元素个数(有效长度)
} SeqList;
void InitSeqList(SeqList* L) {
if (L == NULL) return;
L->length = 0; // 初始无元素
}
int appendElem(SeqList* L, ElemType e)
{
if (L->length >= MAX_SIZE) {
printf("顺序表已满\n");
return 0;
}
L->elem[L->length] = e;
L->length++;
return 1;
}
void listElemp(SeqList* L)
{
for (int i = 0; i < L->length; i++)
{
printf("%d ", L->elem[i]);
}
printf("\n");
}
int findElem(SeqList* L, ElemType e)
{
if (L->length == 0)
{
printf("空列表\n");
return 0;
}
for (int i = 0; i < L->length; i++)
{
if (L->elem[i] == e)
{
return i + 1;
}
}
return 0;
}
int main()
{
//声明一个顺序表并初始化
SeqList list;
InitSeqList(&list);
printf("初始化成功,目前长度占用%d\n", list.length);
printf("目前占用内存%zu字节\n", sizeof(list.elem));
//添加元素
appendElem(&list, 88);
appendElem(&list, 56);
appendElem(&list, 34);
appendElem(&list, 62);
appendElem(&list, 45);
printf("原序列:");
listElemp(&list);
//查找
printf("元素62在表中位置:%d\n", findElem(&list, 62));
return 0;
}
运行结果:
初始化、添加、插入、删除、查找、遍历全部完整代码
#include<stdio.h>
#include<stdlib.h>
#define MAX_SIZE 100
typedef int ElemType;
typedef struct {
ElemType elem[MAX_SIZE]; // 存储元素的数组
int length; // 当前元素个数(有效长度)
} SeqList;
void InitSeqList(SeqList* L) {
if (L == NULL) return;
L->length = 0; // 初始无元素
}
int appendElem(SeqList* L, ElemType e)
{
if (L->length >= MAX_SIZE) {
printf("顺序表已满\n");
return 0;
}
L->elem[L->length] = e;
L->length++;
return 1;
}
void listElemp(SeqList* L)
{
for (int i = 0; i < L->length; i++)
{
printf("%d ", L->elem[i]);
}
printf("\n");
}
int insertElem(SeqList* L, int pos, ElemType e)
{
if (L->length >= MAX_SIZE)
{
printf("表已经满了\n");
return 0;
}
if (pos<1 || pos > L->length)
{
printf("插入位置错误\n");
return 0;
}
if (pos <= L->length)
{
for (int i = L->length - 1; i >= pos - 1; i--)
{
L->elem[i + 1] = L->elem[i];
}
L->elem[pos - 1] = e;
L->length++;
}
return 1;
}
int delectElem(SeqList* L, int pos, ElemType *e)
{
if (L->length == 0)
{
printf("空表\n");
return 0;
}
if (pos < 0 || pos >= L->length)
{
printf("删除失败:删除位置有误\n");
return 0;
}
//保存删除的元素
*e = L->elem[pos - 1];
if (pos < L->length)
{
for (int i = pos; i < L->length; i++)
{
L->elem[i - 1] = L->elem[i];
}
}
L->length--;
return 1;
}
int findElem(SeqList* L, ElemType e)
{
if (L->length == 0)
{
printf("空列表\n");
return 0;
}
for (int i = 0; i < L->length; i++)
{
if (L->elem[i] == e)
{
return i + 1;
}
}
return 0;
}
int main()
{
//声明一个顺序表并初始化
SeqList list;
InitSeqList(&list);
printf("初始化成功,目前长度占用%d\n", list.length);
printf("目前占用内存%zu字节\n", sizeof(list.elem));
appendElem(&list, 88);
appendElem(&list, 56);
appendElem(&list, 34);
appendElem(&list, 62);
appendElem(&list, 45);
printf("原序列:");
listElemp(&list);
insertElem(&list, 2, 24);
printf("插入新元素后:");
listElemp(&list);
ElemType delect;
delectElem(&list, 3, &delect);
printf("被删除的数据为:%d\n", delect);
printf("删除元素后:");
listElemp(&list);
printf("元素62在表中位置:%d\n", findElem(&list, 62));
return 0;
}
动态分配内存地址初始化
// 顺序表结构体:动态数组+当前长度
typedef struct {
ElemType* elem;// 指向存储元素的动态数组
int length; // 当前有效元素个数(而非容量)
}SeqList;
SeqList * initList()
{
//为顺序表结构体分配内存
SeqList* L = (SeqList*)malloc(sizeof(SeqList));
//为存储元素的数组分配内存
L->elem = (ElemType*)malloc(sizeof(ElemType) * MAX_SIZE);
//初始化有效长度为0
L->length = 0;
return L;
}
添加、插入、删除、遍历元素代码与上面相同
完整代码:
#include<stdio.h>
#include<stdlib.h>
#define MAX_SIZE 100
typedef int ElemType;
// 顺序表结构体:动态数组+当前长度
typedef struct {
ElemType* elem;// 指向存储元素的动态数组
int length; // 当前有效元素个数(而非容量)
}SeqList;
SeqList * initList()
{
//为顺序表结构体分配内存
SeqList* L = (SeqList*)malloc(sizeof(SeqList));
//为存储元素的数组分配内存
L->elem = (ElemType*)malloc(sizeof(ElemType) * MAX_SIZE);
//初始化有效长度为0
L->length = 0;
return L;
}
int appendElem(SeqList* L, ElemType e)
{
if (L->length >= MAX_SIZE) {
printf("顺序表已满\n");
return 0;
}
L->elem[L->length] = e;
L->length++;
return 1;
}
void listElemp(SeqList* L)
{
for (int i = 0; i < L->length; i++)
{
printf("%d ", L->elem[i]);
}
printf("\n");
}
int insertElem(SeqList* L, int pos, ElemType e)
{
if (L->length >= MAX_SIZE)
{
printf("表已经满了\n");
return 0;
}
if (pos<1 || pos > L->length)
{
printf("插入位置错误\n");
return 0;
}
if (pos <= L->length)
{
for (int i = L->length - 1; i >= pos - 1; i--)
{
L->elem[i + 1] = L->elem[i];
}
L->elem[pos - 1] = e;
L->length++;
}
return 1;
}
int delectElem(SeqList* L, int pos, ElemType* e)
{
if (L->length == 0)
{
printf("空表\n");
return 0;
}
if (pos < 0 || pos >= L->length)
{
printf("删除失败:删除位置有误\n");
return 0;
}
//保存删除的元素
*e = L->elem[pos - 1];
if (pos < L->length)
{
for (int i = pos; i < L->length; i++)
{
L->elem[i - 1] = L->elem[i];
}
}
L->length--;
return 1;
}
int findElem(SeqList* L, ElemType e)
{
if (L->length == 0)
{
printf("空列表\n");
return 0;
}
for (int i = 0; i < L->length; i++)
{
if (L->elem[i] == e)
{
return i + 1;
}
}
return 0;
}
int main()
{
//声明一个顺序表并初始化
SeqList* list = initList();
appendElem(list, 88);//直接创建指针,直接代入list
appendElem(list, 56);
appendElem(list, 34);
appendElem(list, 62);
appendElem(list, 45);
printf("原序列:");
listElemp(list);
printf("插入数据24在第二个位置\n");
insertElem(list, 2, 24);
printf("插入新元素后:");
listElemp(list);
ElemType delect;
delectElem(list, 3, &delect);
printf("被删除的数据为:%d\n", delect);
printf("删除元素后:");
listElemp(list);
printf("元素62在表中位置:%d\n", findElem(list, 62));
return 0;
}
运行结果:
线性表的顺序存储形式(顺序表)有哪些点让你觉得麻烦?
插入数据、删除数据得移动位置,怎么解决?链表