目录
一、线性表的特点
-
逻辑结构:
- 具有线性结构,有表头(没有前驱)、有表尾(没有后继)。
- 有且只有一个直接前驱和一个直接后继。
-
操作规则:
- 任意位置插入和删除数据。
二、顺序表
-
顺序表与线性表的关系:
顺序表是线性表的顺序存储结构。 -
Length与Size:
- Length表示当前顺序表中的元素个数。
- Size表示顺序表的总容量。
-
判空与判满:
- 顺序表为空:
Length == 0
。 - 顺序表已满:
Length == Size
。
- 顺序表为空:
4.用C语言实现顺序表
1.构造存储结构
#define MAX_SIZE 8
typedef int DataType;
typedef struct {
DataType data[MAX_SIZE];
int length;
} SeqList;
2.初始化
/* 初始化 */
void initSeqList(SeqList *list) {
list->length = 0;
}
3.插入数据
/* 插入数据 */
void insert(SeqList *list, int index, DataType data) {
if (list->length >= MAX_SIZE) {
printf("顺序表已满,无法插入数据\n");
return;
}
if (index < 0 || index > list->length) {
printf("插入位置不合法\n");
return;
}
for (int i = list->length; i > index; --i) {
list->data[i] = list->data[i - 1];
}
list->data[index] = data;
++list->length;
}
4.删除数据
/* 删除数据 */
void delete(SeqList *list, int index) {
if (index < 0 || index >= list->length) {
printf("删除位置不合法\n");
return;
}
for (int i = index; i < list->length - 1; ++i) {
list->data[i] = list->data[i + 1];
}
--list->length;
}
5.判断顺序表是否为空
/* 判断顺序表是否为空 */
int isEmpty(SeqList *list) {
return list->length == 0;
}
6.判断顺序表是否已满
/* 判断顺序表是否已满 */
int isFull(SeqList *list) {
return list->length == MAX_SIZE;
}
5.练习题
1.有序递增插入数据
/* 有序递增插入数据 */
void insertSorted(SeqList *list, DataType data) {
int i = 0;
while (i < list->length && data > list->data[i]) {
++i;
}
insert(list, i, data);
}
2.有序递增删除数据
/* 有序递增删除数据 */
void deleteSorted(SeqList *list, DataType data) {
int i = 0;
while (i < list->length && data != list->data[i]) {
++i;
}
if (i < list->length) {
delete(list, i);
} else {
printf("数据 %d 不在顺序表中\n", data);
}
}
3.遍历打印顺序表
/* 遍历打印顺序表 */
void printList(SeqList *list) {
for (int i = 0; i < list->length; ++i) {
printf("%d\t", list->data[i]);
}
printf("\n");
}
4.主函数
int main() {
SeqList list;
initSeqList(&list);
int input;
while (1) {
printf("请输入正整数插入数据,负整数删除数据,0结束:");
scanf("%d", &input);
if (input == 0) {
break;
} else if (input > 0) {
if (!isFull(&list)) {
insertSorted(&list, input);
printList(&list);
} else {
printf("顺序表已满,无法插入数据\n");
}
} else if (input < 0) {
if (!isEmpty(&list)) {
deleteSorted(&list, -input);
printList(&list);
} else {
printf("顺序表为空,无法删除数据\n");
}
}
}
return 0;
}
三、链表
链表的基本概念
链表是一种基本的数据结构,与顺序表相比,链表具有以下特点:
-
逻辑结构:
- 仍然是线性结构,但没有表头和表尾的概念。
- 通过指针将结点按照一定的逻辑次序连接起来。
-
存储方式:
- 采用动态存储方式,不需要预先分配存储空间。
-
结点:
- 链表中的每个元素称为结点(Node),每个结点包括数据域和指针域。
- 数据域存储结点的数据。
- 指针域存储指向下一个结点的指针。
单链表
1. 单链表的存储结构
typedef int DataType;
typedef struct Node {
DataType data;
struct Node *next;
} ListNode, *ListPtr;
2. 单链表的基本操作
初始化:
/* 初始化单链表 */
void initList(ListPtr *head) {
*head = (ListPtr)malloc(sizeof(ListNode));
if (*head == NULL) {
printf("内存分配失败\n");
exit(1);
}
(*head)->next = NULL;
}
插入结点:
/* 在位置pos后插入结点 */
void insertNode(ListPtr head, int pos, DataType data) {
if (pos < 0) {
printf("插入位置不合法\n");
return;
}
ListPtr newNode = (ListPtr)malloc(sizeof(ListNode));
if (newNode == NULL) {
printf("内存分配失败\n");
exit(1);
}
newNode->data = data;
newNode->next = NULL;
ListPtr p = head;
for (int i = 0; i < pos && p != NULL; ++i) {
p = p->next;
}
if (p == NULL) {
printf("插入位置不合法\n");
free(newNode);
return;
}
newNode->next = p->next;
p->next = newNode;
}
删除结点:
/* 删除位置pos的结点 */
void deleteNode(ListPtr head, int pos) {
if (pos < 0) {
printf("删除位置不合法\n");
return;
}
ListPtr p = head;
for (int i = 0; i < pos && p != NULL; ++i) {
p = p->next;
}
if (p == NULL || p->next == NULL) {
printf("删除位置不合法\n");
return;
}
ListPtr temp = p->next;
p->next = temp->next;
free(temp);
}
遍历打印单链表:
/* 遍历打印单链表 */
void printList(ListPtr head) {
ListPtr p = head->next;
while (p != NULL) {
printf("%d\t", p->data);
p = p->next;
}
printf("\n");
}
主函数:
int main() {
ListPtr list;
initList(&list);
int input;
while (1) {
printf("请输入正整数插入数据,负整数删除数据,0结束:");
scanf("%d", &input);
if (input == 0) {
break;
} else if (input > 0) {
insertNode(list, list->data, input);
printList(list);
} else if (input < 0) {
deleteNode(list, -input);
printList(list);
}
}
return 0;
}
关系:顺序表和链表是线性表的两种具体实现方式
-
线性表:
- 线性表是一种基本的数据结构,表示具有相同数据类型的元素按照线性次序排列的数据结构。
- 线性表包括了一对一的关系,即每个元素都有一个直接前驱和一个直接后继。
-
顺序表:
- 顺序表是线性表的一种顺序存储结构,它使用数组等连续的存储空间来存储元素。
- 顺序表中的元素在物理内存中是相邻的,通过数组下标可以直接访问元素。
- 顺序表支持随机存取,即可以直接访问表中任意位置的元素。
-
链表:
- 链表是线性表的一种链式存储结构,它通过指针将元素按照一定的逻辑次序连接起来。
- 链表的元素在物理内存中可以是不相邻的,每个元素包含数据域和指针域。
- 链表包括单链表、双链表和循环链表等不同的类型。
-
选择原则:
- 顺序表适用于频繁按位置访问元素的场景,链表适用于频繁插入和删除元素的场景。
- 选择合适的存储方式取决于具体的应用需求。
-
应用场景:
- 顺序表常用于静态查找、索引和需要频繁访问元素的场景。
- 链表常用于动态存储、频繁插入和删除元素的场景。
通过深入理解线性表、顺序表和链表的特点和实现方式,我们能够更好地选择和设计数据结构,以满足不同问题的需求。在实际应用中,合理选择和灵活运用这些数据结构能够提高程序的效率和性能。