线性表的定义
线性表是指具有相同数据类型的 n 个数据元素的有限序列。可以用如下方式表示:
[ L = (a_1, a_2, …, a_i, …, a_n) ]
其中:
- ( a_1 ) 是第一个元素,称为表头。
- ( a_n ) 是最后一个元素,称为表尾。
- 对于任意元素 ( a_i ),它有且仅有一个前驱元素 ( a_{i-1} )(除第一个元素)和一个后继元素 ( a_{i+1} )(除最后一个元素)。
线性表的特点
- 有序性:线性表中的元素按逻辑顺序排列,即每个元素有且仅有一个前驱和一个后继。
- 唯一性:每个元素在表中的位置是唯一的。
- 有限性:线性表中元素的个数是有限的。
- 类型一致性:线性表中的所有元素具有相同的数据类型。
线性表的抽象数据类型(ADT)
抽象数据类型(ADT)是一个数学模型及定义在该模型上的一组操作。对于线性表,其抽象数据类型的描述包括数据对象、数据关系以及操作。
数据对象
线性表中的数据对象是具有相同类型的数据元素的有序序列。
数据关系
线性表中的数据元素之间存在前驱和后继关系,即对任意元素 ( a_i ),有一个前驱元素 ( a_{i-1} ) 和一个后继元素 ( a_{i+1} )(除第一个和最后一个元素)。
操作
线性表的基本操作包括:
- 初始化:创建一个空的线性表。
- 销毁:销毁线性表,释放其占用的内存空间。
- 插入:在指定位置插入一个元素。
- 删除:删除指定位置的元素。
- 查找:查找并返回指定元素的位置。
- 取值:获取指定位置的元素。
- 修改:修改指定位置的元素。
- 长度:返回线性表的长度(元素个数)。
- 判空:判断线性表是否为空。
顺序存储结构的实现
顺序存储结构是用一组地址连续的存储单元依次存储线性表中的各个元素,通常使用数组来实现。
以下是线性表的顺序存储结构及其操作的详细实现示例:
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#define MAXSIZE 100 // 线性表的最大长度
typedef int ElemType; // 定义线性表中的元素类型
typedef struct {
ElemType data[MAXSIZE]; // 存储线性表的元素
int length; // 线性表的当前长度
} LinearList;
// 初始化线性表
void InitList(LinearList *L) {
L->length = 0; // 初始化长度为0
}
// 销毁线性表
void DestroyList(LinearList *L) {
// 对于顺序存储结构,不需要额外释放内存
L->length = 0;
}
// 插入元素
bool InsertElement(LinearList *L, int position, ElemType element) {
if (position < 1 || position > L->length + 1) {
return false; // 插入位置不合法
}
if (L->length == MAXSIZE) {
return false; // 线性表已满
}
for (int i = L->length; i >= position; i--) {
L->data[i] = L->data[i - 1]; // 元素后移
}
L->data[position - 1] = element; // 插入元素
L->length++; // 长度加1
return true;
}
// 删除元素
bool DeleteElement(LinearList *L, int position) {
if (position < 1 || position > L->length) {
return false; // 删除位置不合法
}
for (int i = position; i < L->length; i++) {
L->data[i - 1] = L->data[i]; // 元素前移
}
L->length--; // 长度减1
return true;
}
// 查找元素
int LocateElement(LinearList *L, ElemType element) {
for (int i = 0; i < L->length; i++) {
if (L->data[i] == element) {
return i + 1; // 返回位置,位置从1开始
}
}
return 0; // 元素不存在
}
// 获取元素
ElemType GetElement(LinearList *L, int position) {
if (position < 1 || position > L->length) {
exit(EXIT_FAILURE); // 位置不合法,退出程序
}
return L->data[position - 1];
}
// 修改元素
bool SetElement(LinearList *L, int position, ElemType element) {
if (position < 1 || position > L->length) {
return false; // 修改位置不合法
}
L->data[position - 1] = element;
return true;
}
// 获取线性表长度
int ListLength(LinearList *L) {
return L->length;
}
// 判断线性表是否为空
bool IsEmpty(LinearList *L) {
return L->length == 0;
}
int main() {
LinearList list;
InitList(&list);
// 插入元素
InsertElement(&list, 1, 10);
InsertElement(&list, 2, 20);
InsertElement(&list, 3, 30);
// 输出线性表长度
printf("线性表长度: %d\n", ListLength(&list));
// 获取并输出第2个位置的元素
printf("第2个位置的元素: %d\n", GetElement(&list, 2));
// 修改第2个位置的元素
SetElement(&list, 2, 25);
// 删除第1个位置的元素
DeleteElement(&list, 1);
// 查找元素
int pos = LocateElement(&list, 30);
if (pos) {
printf("元素30的位置: %d\n", pos);
} else {
printf("元素30不存在\n");
}
// 判断线性表是否为空
printf("线性表是否为空: %d\n", IsEmpty(&list));
DestroyList(&list);
return 0;
}
链式存储结构的实现
链式存储结构是用一组任意的存储单元存放线性表中的元素,不要求地址连续,通过指针将这些存储单元链接起来。
以下是线性表的链式存储结构及其操作的详细实现示例:
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
typedef int ElemType; // 定义线性表中的元素类型
typedef struct Node {
ElemType data; // 存储元素
struct Node *next; // 指向下一个节点的指针
} Node;
typedef struct {
Node *head; // 头指针,指向链表的第一个节点
int length; // 链表的长度
} LinkedList;
// 初始化链表
void InitList(LinkedList *L) {
L->head = (Node *)malloc(sizeof(Node)); // 创建头节点
L->head->next = NULL; // 头节点指针域置空
L->length = 0; // 初始化长度为0
}
// 销毁链表
void DestroyList(LinkedList *L) {
Node *p = L->head;
while (p) {
Node *temp = p;
p = p->next;
free(temp);
}
L->length = 0;
}
// 插入元素
bool InsertElement(LinkedList *L, int position, ElemType element) {
if (position < 1 || position > L->length + 1) {
return false; // 插入位置不合法
}
Node *p = L->head;
int i = 0;
while (i < position - 1) {
p = p->next;
i++;
}
Node *newNode = (Node *)malloc(sizeof(Node)); // 创建新节点
newNode->data = element;
newNode->next = p->next;
p->next = newNode;
L->length++;
return true;
}
// 删除元素
bool DeleteElement(LinkedList *L, int position) {
if (position < 1 || position > L->length) {
return false;
// 删除位置不合法
}
Node *p = L->head;
int i = 0;
while (i < position - 1) {
p = p->next;
i++;
}
Node *temp = p->next;
p->next = temp->next;
free(temp);
L->length--;
return true;
}
// 查找元素
int LocateElement(LinkedList *L, ElemType element) {
Node *p = L->head->next;
int position = 1;
while (p) {
if (p->data == element) {
return position;
}
p = p->next;
position++;
}
return 0; // 元素不存在
}
// 获取元素
ElemType GetElement(LinkedList *L, int position) {
if (position < 1 || position > L->length) {
exit(EXIT_FAILURE); // 位置不合法,退出程序
}
Node *p = L->head->next;
int i = 1;
while (i < position) {
p = p->next;
i++;
}
return p->data;
}
// 修改元素
bool SetElement(LinkedList *L, int position, ElemType element) {
if (position < 1 || position > L->length) {
return false; // 修改位置不合法
}
Node *p = L->head->next;
int i = 1;
while (i < position) {
p = p->next;
i++;
}
p->data = element;
return true;
}
// 获取链表长度
int ListLength(LinkedList *L) {
return L->length;
}
// 判断链表是否为空
bool IsEmpty(LinkedList *L) {
return L->length == 0;
}
int main() {
LinkedList list;
InitList(&list);
// 插入元素
InsertElement(&list, 1, 10);
InsertElement(&list, 2, 20);
InsertElement(&list, 3, 30);
// 输出链表长度
printf("链表长度: %d\n", ListLength(&list));
// 获取并输出第2个位置的元素
printf("第2个位置的元素: %d\n", GetElement(&list, 2));
// 修改第2个位置的元素
SetElement(&list, 2, 25);
// 删除第1个位置的元素
DeleteElement(&list, 1);
// 查找元素
int pos = LocateElement(&list, 30);
if (pos) {
printf("元素30的位置: %d\n", pos);
} else {
printf("元素30不存在\n");
}
// 判断链表是否为空
printf("链表是否为空: %d\n", IsEmpty(&list));
DestroyList(&list);
return 0;
}