1
0
mirror of https://github.com/Didnelpsun/CS408.git synced 2026-06-18 01:19:14 +08:00

更新线性表部分

This commit is contained in:
Didnelpsun
2021-04-19 23:30:19 +08:00
parent 09f80d310c
commit 0408e3d542
4 changed files with 447 additions and 6 deletions

186
Code/double_link_list.h Normal file
View File

@@ -0,0 +1,186 @@
#include <stdio.h>
#include <stdlib.h>
#include "head.h"
// 双链表结点
typedef struct DoubleLinkNode{
element_type data;
struct DoubleLinkNode* prior, * next;
} DoubleLinkNode, *DoubleLinkList;
// 初始化有头节点双链表
int InitDoubleLinkListWithHead(DoubleLinkList list) {
list = (DoubleLinkNode*)malloc(sizeof(DoubleLinkNode));
// 分配内存失败
if (list == NULL) {
printf("InitDoubleLinkListWithHead:初始化分配内存失败!");
return 1;
}
// 头结点的前驱结点始终为NULL
list->prior = NULL;
list->next = NULL;
return 0;
}
// 判断有头节点双链表是否为空
int IsDoubleLinkListEmptyWithHead(DoubleLinkList list) {
if (list->next == NULL) {
return 1;
}
else {
return 0;
}
}
// 后插入双链表元素
int InsertNextDoubleLinkNode(DoubleLinkNode* node, element_type elem) {
if (node == NULL) {
printf("InsertNextDoubleLinkNode:插入结点为空!");
return 1;
}
DoubleLinkNode* s = (DoubleLinkNode*)malloc(sizeof(DoubleLinkNode));
// 如果分配空间失败
if (s == NULL) {
printf("InsertNextDoubleLinkNode:分配内存失败!\n");
return 1;
}
s->data = elem;
// 将新建结点s插入结点node后
s->next = node->next;
// 如果有后继结点将p原来的后继给s结点
if (node->next->prior) {
node->next->prior = s;
}
// 交换s的前驱和后继
s->prior = node;
node->next = s;
return 0;
}
// 前插入双链表元素
int InsertPriorDoubleLinkNode(DoubleLinkNode* node, element_type elem) {
if (node == NULL) {
printf("InsertPriorDoubleLinkNode:插入结点为空!");
return 1;
}
DoubleLinkNode* s = (DoubleLinkNode*)malloc(sizeof(DoubleLinkNode));
// 如果分配空间失败
if (s == NULL) {
printf("InsertPriorDoubleLinkNode:分配内存失败!\n");
return 1;
}
s->next = node->next;
node->next = s;
s->data = node->data;
node->data = elem;
return 0;
}
// 删除双链表后续结点
int DeleteNextDoubleLinkListNode(DoubleLinkNode* node) {
if (node == NULL) {
printf("DeleteDoubleLinkListNode:删除结点为空!");
return 1;
}
DoubleLinkNode* p = node->next;
if (p == NULL) {
printf("DeleteDoubleLinkListNode:删除结点后续结点为空!");
return 1;
}
node->next = p->next;
// 如果p结点为最后一个结点
if (p->next != NULL) {
p->next->prior = node;
}
free(p);
return 0;
}
// 销毁双链表
int DestroyDoubleLinkList(DoubleLinkList list) {
// 循环删除各个结点
while (list->next != NULL) {
DeleteNextDoubleLinkListNode(list);
}
// 释放头结点
free(list);
list = NULL;
return 0;
}
// 初始化有头节点循环双链表
int InitCircularDoubleLinkListWithHead(DoubleLinkList list) {
list = (DoubleLinkNode*)malloc(sizeof(DoubleLinkNode));
if (list == NULL) {
printf("InitCircularDoubleLinkListWithHead:初始化分配内存失败!");
return 1;
}
// 前后指针都指向其本身
list->next = list;
list->prior = list;
return 0;
}
// 判断有头节点循环双链表是否为空
int IsCircularDoubleLinkListEmptyWithHead(DoubleLinkList list) {
if (list->next == list) {
return 1;
}
else {
return 0;
}
}
// 判断结点是否尾有头节点循环双链表的尾结点
int IsCircularDoubleLinkListEndWithHead(DoubleLinkList list, DoubleLinkNode* node) {
if (node->next == list) {
return 1;
}
else {
return 0;
}
}
// 后插入循环双链表元素
// 与双链表一样唯一区别就是不用判别后一个元素是否为NULL因为是连接在一起的
int InsertNextCircularDoubleLinkNode(DoubleLinkNode* node, element_type elem) {
if (node == NULL) {
printf("InsertNextDoubleLinkNode:插入结点为空!");
return 1;
}
DoubleLinkNode* s = (DoubleLinkNode*)malloc(sizeof(DoubleLinkNode));
// 如果分配空间失败
if (s == NULL) {
printf("InsertNextDoubleLinkNode:分配内存失败!\n");
return 1;
}
s->data = elem;
// 将新建结点s插入结点node后
s->next = node->next;
// 不同之处一定有后继结点将p原来的后继给s结点
node->next->prior = s;
// 交换s的前驱和后继
s->prior = node;
node->next = s;
return 0;
}
// 删除循环双链表后续结点
// 与双链表一样唯一区别就是不用判别后一个元素是否为NULL因为是连接在一起的
int DeleteNextCircularDoubleLinkListNode(DoubleLinkNode* node) {
if (node == NULL) {
printf("DeleteDoubleLinkListNode:删除结点为空!");
return 1;
}
DoubleLinkNode* p = node->next;
if (p == NULL) {
printf("DeleteDoubleLinkListNode:删除结点后续结点为空!");
return 1;
}
node->next = p->next;
// 不同之处
p->next->prior = node;
free(p);
return 0;
}

View File

@@ -2,8 +2,8 @@
#include <stdlib.h>
#include "head.h"
// 链表结点
typedef struct {
// 链表结点
typedef struct LinkNode {
element_type data;
struct LinkNode* next;
} LinkNode, *LinkList;
@@ -12,6 +12,7 @@ typedef struct {
int InitLinkListWithHead(LinkList list) {
list = (LinkNode*)malloc(sizeof(LinkNode));
if (list == NULL) {
printf("InitLinkListWithHead:初始化分配内存失败!");
return 1;
}
list->next = NULL;
@@ -25,7 +26,7 @@ int InitLinkListWithoutHead(LinkList list) {
}
// 判断有头节点单链表是否为空
int IsLLinkListEmptyWithHead(LinkList list) {
int IsLinkListEmptyWithHead(LinkList list) {
if (list->next == NULL) {
return 1;
}
@@ -128,6 +129,7 @@ int InsertLinkListWithoutHead(LinkList list, int index, element_type elem) {
// 后插入单链表元素
int InsertNextLinkNode(LinkNode* node, element_type elem) {
if (node == NULL) {
printf("InsertNextLinkNode:插入结点为空!");
return 1;
}
LinkNode* s = (LinkNode*)malloc(sizeof(LinkNode));
@@ -145,6 +147,7 @@ int InsertNextLinkNode(LinkNode* node, element_type elem) {
// 前插入单链表元素
int InsertPriorLinkNode(LinkNode* node, element_type elem) {
if (node == NULL) {
printf("InsertPriorLinkNode:插入结点为空!");
return 1;
}
LinkNode* s = (LinkNode*)malloc(sizeof(LinkNode));
@@ -321,7 +324,7 @@ int GetLength(LinkList list) {
}
// 后插建立带头节点单链表
LinkList TailBuildLinkListWithHead(LinkList* list, int length) {
LinkList TailBuildLinkListWithHead(LinkList list, int length) {
element_type elem;
list = (LinkList)malloc(sizeof(LinkNode));
// s指针为一个中间变量指针r指针为尾指针next指向最后一个元素
@@ -340,4 +343,62 @@ LinkList TailBuildLinkListWithHead(LinkList* list, int length) {
r = s;
i++;
}
r->next = NULL;
return list;
}
// 前插建立带头节点单链表
LinkList HeadBuildLinkListWithHead(LinkList list, int length) {
element_type elem;
list = (LinkList)malloc(sizeof(LinkNode));
// 将单链表尾部设置为NULL
list->next = NULL;
// s指针为一个中间变量指针
LinkNode* s;
int i = 0;
element_type x;
if (length < 1) {
printf("HeadBuildLinkListWithHead:输入的单链表长度过小!");
return 1;
}
while (i < length) {
scanf("%d", &x);
s = (LinkNode*)malloc(sizeof(LinkNode));
s->data = x;
s->next = list->next;
list->next = s;
i++;
}
return list;
}
// 初始化有头节点循环单链表
int InitCircularLinkListWithHead(LinkList list) {
list = (LinkNode*)malloc(sizeof(LinkNode));
if (list == NULL) {
printf("InitCircularLinkListWithHead:初始化分配内存失败!");
return 1;
}
list->next = list;
return 0;
}
// 判断有头节点循环单链表是否为空
int IsCircularLinkListEmptyWithHead(LinkList list) {
if (list->next == list) {
return 1;
}
else {
return 0;
}
}
// 判断结点是否尾有头节点循环单链表的尾结点
int IsCircularLinkListEndWithHead(LinkList list, LinkNode* node) {
if (node->next == list) {
return 1;
}
else {
return 0;
}
}

10
Code/static_link_list.h Normal file
View File

@@ -0,0 +1,10 @@
#include <stdio.h>
#include <stdlib.h>
#include "head.h"
// 静态链表结点
typedef struct StaticLinkNode {
element_type data;
// 下一个元素的数组下标
int next;
} DoubleLinkNode, * DoubleLinkList;

View File

@@ -306,7 +306,7 @@ int LocateDynamicSequenceListElement(DynamicSequenceList list, element_type elem
```c
// 链表结点
typedef struct {
typedef struct LinkNode {
element_type data;
struct LinkNode* next;
} LinkNode, *LinkList;
@@ -331,6 +331,7 @@ int InitLinkListWithoutHead(LinkList list) {
int InitLinkListWithHead(LinkList list) {
list = (LinkNode*)malloc(sizeof(LinkNode));
if (list == NULL) {
printf("InitLinkListWithHead:初始化分配内存失败!");
return 1;
}
list->next = NULL;
@@ -456,6 +457,7 @@ int InsertLinkListWithoutHead(LinkList list, int index, element_type elem) {
// 后插入单链表元素
int InsertNextLinkNode(LinkNode* node, element_type elem) {
if (node == NULL) {
printf("InsertNextLinkNode:插入结点为空!");
return 1;
}
LinkNode* s = (LinkNode*)malloc(sizeof(LinkNode));
@@ -481,6 +483,7 @@ int InsertNextLinkNode(LinkNode* node, element_type elem) {
// 前插入单链表元素
int InsertPriorLinkNode(LinkNode* node, element_type elem) {
if (node == NULL) {
printf("InsertPriorLinkNode:插入结点为空!");
return 1;
}
LinkNode* s = (LinkNode*)malloc(sizeof(LinkNode));
@@ -679,4 +682,185 @@ LinkNode* LocateLinkListNode(LinkList list, element_type elem) {
#### 单链表建立
可以使用尾插法建立单链表,从后面不断插入元素。
可以使用尾插法建立单链表,从后面不断插入元素。需要定义一个尾指针来记录最后一位。
```c
// 后插建立带头节点单链表
LinkList TailBuildLinkListWithHead(LinkList list, int length) {
element_type elem;
list = (LinkList)malloc(sizeof(LinkNode));
// s指针为一个中间变量指针r指针为尾指针next指向最后一个元素
LinkNode* s, * r = list;
int i = 0;
element_type x;
if (length < 1) {
printf("TailBuildLinkListWithHead:输入的单链表长度过小!");
return 1;
}
while (i < length) {
scanf("%d", &x);
s = (LinkNode*)malloc(sizeof(LinkNode));
s->data = x;
r->next = s;
r = s;
i++;
}
r->next = NULL;
return list;
}
```
使用前插法建立单链表实际上也是使用后插操作,不过每一次后插的元素都是头结点,也不用使用尾指针。
前插法可以实现链表的逆置。
```c
// 前插建立带头节点单链表
LinkList HeadBuildLinkListWithHead(LinkList list, int length) {
element_type elem;
list = (LinkList)malloc(sizeof(LinkNode));
// 将单链表尾部设置为NULL
list->next = NULL;
// s指针为一个中间变量指针
LinkNode* s;
int i = 0;
element_type x;
if (length < 1) {
printf("HeadBuildLinkListWithHead:输入的单链表长度过小!");
return 1;
}
while (i < length) {
scanf("%d", &x);
s = (LinkNode*)malloc(sizeof(LinkNode));
s->data = x;
s->next = list->next;
list->next = s;
i++;
}
return list;
}
```
## 双链表
为了解决单链表只能单一方向扫描而无法两项遍历的缺点使用了两个指针prior和next分别指向前驱和后继。
### 双链表定义
基本上与单链表的定义一致。
### 双链表操作
#### 双链表初始化
```c
// 初始化有头节点双链表
int InitDoubleLinkListWithHead(DoubleLinkList list) {
list = (DoubleLinkNode*)malloc(sizeof(DoubleLinkNode));
// 分配内存失败
if (list == NULL) {
printf("InitDoubleLinkListWithHead:初始化分配内存失败!");
return 1;
}
// 头结点的前驱结点始终为NULL
list->prior = NULL;
list->next = NULL;
return 0;
}
```
#### 双链表插入
```c
// 后插入双链表元素
int InsertNextDoubleLinkNode(DoubleLinkNode* node, element_type elem) {
if (node == NULL) {
printf("InsertNextDoubleLinkNode:插入结点为空!");
return 1;
}
DoubleLinkNode* s = (DoubleLinkNode*)malloc(sizeof(DoubleLinkNode));
// 如果分配空间失败
if (s == NULL) {
printf("InsertNextDoubleLinkNode:分配内存失败!\n");
return 1;
}
s->data = elem;
// 将新建结点s插入结点node后
s->next = node->next;
// 如果有后继结点将p原来的后继给s结点
if (node->next->prior) {
node->next->prior = s;
}
// 交换s的前驱和后继
s->prior = node;
node->next = s;
return 0;
}
// 前插入双链表元素
int InsertPriorDoubleLinkNode(DoubleLinkNode* node, element_type elem) {
if (node == NULL) {
printf("InsertPriorDoubleLinkNode:插入结点为空!");
return 1;
}
DoubleLinkNode* s = (DoubleLinkNode*)malloc(sizeof(DoubleLinkNode));
// 如果分配空间失败
if (s == NULL) {
printf("InsertPriorDoubleLinkNode:分配内存失败!\n");
return 1;
}
s->next = node->next;
node->next = s;
s->data = node->data;
node->data = elem;
return 0;
}
```
#### 双链表删除
```c
// 删除双链表后续结点
int DeleteNextDoubleLinkListNode(DoubleLinkNode* node) {
if (node == NULL) {
printf("DeleteDoubleLinkListNode:删除结点为空!");
return 1;
}
DoubleLinkNode* p = node->next;
if (p == NULL) {
printf("DeleteDoubleLinkListNode:删除结点后续结点为空!");
return 1;
}
node->next = p->next;
// 如果p结点为最后一个结点
if (p->next != NULL) {
p->next->prior = node;
}
free(p);
return 0;
}
```
## 循环链表
分为循环单链表和循环双链表。基本上变化不大。
原来的单链表的尾部指向NULL但是循环单链表的尾部是指向头部。
循环单链表即使没有头结点的地址,也可以通过循环得到整个单链表的信息。
从头到尾单链表需要遍历整个链表,而循环单链表只用移动一位就可以从头到尾。
循环双链表除此之外头结点的prior指针还要指表尾结点即某结点*p为尾结点时p->next==list
循环双链表为空表时头结点的prior和next域都等于list指向自身
## 静态链表
静态链表借助数组来描述线性表的链式存储结构,结点也有数据域和指针域,这里的指针是结点的相对地址(数组下标),又称游标。
静态链表和顺序表一样需要预先分配一块连续的内存空间。
数组0号元素充当链表的头结点且不包含数据。
如果一个结点是尾结点,其游标设置为-1。