diff --git a/Code/Code.vcxproj b/Code/Code.vcxproj index 04d046a..e246564 100644 --- a/Code/Code.vcxproj +++ b/Code/Code.vcxproj @@ -140,7 +140,11 @@ - + + + + + diff --git a/Code/Code.vcxproj.filters b/Code/Code.vcxproj.filters index 9a0b995..2dc6959 100644 --- a/Code/Code.vcxproj.filters +++ b/Code/Code.vcxproj.filters @@ -15,11 +15,19 @@ - - 源文件 - 头文件 + + 源文件 + + + + + 头文件 + + + 头文件 + \ No newline at end of file diff --git a/Code/head.h b/Code/head.h index 091a856..d290b76 100644 --- a/Code/head.h +++ b/Code/head.h @@ -1,3 +1,4 @@ // ʼ󳤶 #define MAXSIZE 25 -typedef int element_type; \ No newline at end of file +#define DEFAULTELEM 0 +typedef int element_type; diff --git a/Code/linear_list.c b/Code/linear_list.c deleted file mode 100644 index b76c4ac..0000000 --- a/Code/linear_list.c +++ /dev/null @@ -1,76 +0,0 @@ -#include -#include -#include "head.h" - -// 静态顺序表 -typedef struct { - element_type data[MAXSIZE]; - int length; -} StaticSequenceList; - -// 动态顺序表 -typedef struct { - element_type *data; - // 已分配的最大容量 - int max_size; - int length; -} DynamicSequenceList; - -// 初始化静态顺序表 -void InitStaticSequenceList(StaticSequenceList* list) { - // 初初始化静态顺序表长度为0 - list->length = 0; -} - -// 初始化动态顺序表 -void InitDynamicSequenceList(DynamicSequenceList* list) { - // 初初始化动态顺序表长度为0 - list->length = 0; - // 申请一片连续的存储空间 - list->data = (element_type*)malloc(MAXSIZE * sizeof(element_type)); - list->max_size = MAXSIZE; -} - -// 分配其他地址增长动态顺序表的数据空间长度 -void OtherIncreaseDynamicSequenceList(DynamicSequenceList* list, int len) { - // 申请一片连续的存储空间 - int new_length = list->max_size + len; - element_type* space = (element_type*)realloc(list->data, new_length); - if (space != NULL) { - list->data = space; - list->max_size += len; - } - else { - list->max_size = 0; - list->length = 0; - printf("分配空间失败!"); - } -} - -// 重新分配地址增长动态顺序表的数据空间长度 -void ReIncreaseDynamicSequenceList(DynamicSequenceList* list, int len) { - // 申请一片连续的存储空间 - int new_length = list->max_size + len; - element_type* space = (element_type*)realloc(list->data, new_length); - if (space != NULL) { - list->data = space; - list->max_size += len; - } - else { - list->max_size = 0; - list->length = 0; - printf("分配空间失败!"); - } -} - -int main() -{ - /*StaticSequenceList static_list; - InitStaticSequenceList(&static_list);*/ - DynamicSequenceList dynamic_list; - InitDynamicSequenceList(&dynamic_list); - printf("%d\n", dynamic_list.max_size); - ReIncreaseDynamicSequenceList(&dynamic_list, 25); - printf("%d\n", dynamic_list.max_size); - return 0; -} \ No newline at end of file diff --git a/Code/link_list.h b/Code/link_list.h new file mode 100644 index 0000000..b75ae55 --- /dev/null +++ b/Code/link_list.h @@ -0,0 +1,161 @@ +#include +#include +#include "head.h" + +// 链表结点 +typedef struct { + element_type data; + struct LinkNode* next; +} LinkNode, *LinkList; + +// 初始化有头节点单链表 +int InitLinkListWithHead(LinkList list) { + list = (LinkNode*)malloc(sizeof(LinkNode)); + if (list == NULL) { + return 1; + } + list->next = NULL; + return 0; +} + +// 初始化无头节点单链表 +int InitLinkListWithoutHead(LinkList list) { + list = NULL; + return 0; +} + +// 判断有头节点单链表是否为空 +int IsLLinkListEmptyWithHead(LinkList list) { + if (list->next == NULL) { + return 1; + } + else { + return 0; + } +} + +// 判断无头节点单链表是否为空 +int IsLLinkListEmptyWithoutHead(LinkList list) { + if (list == NULL) { + return 1; + } + else { + return 0; + } +} + +// 插入有头节点单链表元素 +int InsertLinkListWithHead(LinkList list, int index, element_type elem) { + if (index < 1) { + printf("InsertLinkListWithHead:插入索引值过小!\n"); + return 1; + } + // 定义一个结点指针p指向当前扫描到的结点 + LinkNode* p; + // 定义一个变量i表示当前扫描到的结点的索引号 + int i = 0; + // 将链表头结点指向p,为第0个结点 + p = list; + // 循环遍历到达指定索引号的单链表的结点 + // 条件是当前结点的下一个不为空且索引号到达,所到达的结点一定不是空结点 + while (p->next != NULL && i < index-1) { + p = p->next; + i++; + } + // 如果此时i小于index-1,表示遍历完还没有到达对应的索引 + if (i < index-1) { + printf("InsertLinkListWithHead:插入索引值过大!\n"); + return 1; + } + // 此时i==index-1 + LinkNode* s = (LinkNode*)malloc(sizeof(LinkNode)); + if (s == NULL) { + printf("InsertLinkListWithHead:分配内存失败!\n"); + return 1; + } + s->data = elem; + // 将p原来的后继给新的结点 + s->next = p->next; + p->next = s; + return 0; +} + +// 插入无头节点单链表元素 +int InsertLinkListWithoutHead(LinkList list, int index, element_type elem) { + if (index < 0) { + printf("InsertLinkListWithoutHead:插入索引值过小!\n"); + return 1; + } + if (index == 0) { + LinkNode* s = (LinkNode*)malloc(sizeof(LinkNode)); + if (s == NULL) { + printf("InsertLinkListWithoutHead:分配内存失败!\n"); + return 1; + } + s->data = elem; + // 将s的后继设为list指针 + s->next = list; + // 将list指针设置为s指针 + list = s; + return 0; + } + // 定义一个结点指针p指向当前扫描到的结点 + LinkNode* p; + // 定义一个变量i表示当前扫描到的结点的索引号 + int i = 0; + // 将链表头结点指向p,为第0个结点 + p = list; + // 循环遍历到达指定索引号的单链表的结点 + // 条件是当前结点的下一个不为空且索引号到达,所到达的结点一定不是空结点 + while (p->next != NULL && i < index - 1) { + p = p->next; + i++; + } + // 如果此时i小于index-1,表示遍历完还没有到达对应的索引 + if (i < index - 1) { + printf("InsertLinkListWithoutHead:插入索引值过大!\n"); + return 1; + } + // 此时i==index-1 + LinkNode* s = (LinkNode*)malloc(sizeof(LinkNode)); + s->data = elem; + // 将p原来的后继给新的结点 + s->next = p->next; + p->next = s; + return 0; +} + +// 后插入单链表元素 +int InsertNextLinkNode(LinkNode* node, element_type elem) { + if (node == NULL) { + return 1; + } + LinkNode* s = (LinkNode*)malloc(sizeof(LinkNode)); + // 如果分配空间失败 + if (s == NULL) { + printf("InsertNextLinkNode:分配内存失败!\n"); + return 1; + } + s->data = elem; + s->next = node->next; + node->next = s; + return 0; +} + +// 前插入单链表元素 +int InsertPriorLinkNode(LinkNode* node, element_type elem) { + if (node == NULL) { + return 1; + } + LinkNode* s = (LinkNode*)malloc(sizeof(LinkNode)); + // 如果分配空间失败 + if (s == NULL) { + printf("InsertPriorLinkNode:分配内存失败!\n"); + return 1; + } + s->next = node->next; + node->next = s; + s->data = node->data; + node->data = elem; + return 0; +} \ No newline at end of file diff --git a/Code/main.c b/Code/main.c new file mode 100644 index 0000000..e017379 --- /dev/null +++ b/Code/main.c @@ -0,0 +1,30 @@ +#include +#include +#include "head.h" +#include "sequence_list.h" +#include "link_list.h" + +int main() +{ + /*StaticSequenceList static_list; + InitStaticSequenceList(&static_list); + DynamicSequenceList dynamic_list; + InitDynamicSequenceList(&dynamic_list); + printf("%d\n", dynamic_list.max_size); + ReIncreaseDynamicSequenceList(&dynamic_list, 25); + printf("%d\n", dynamic_list.max_size); + InsertStaticSequenceList(&static_list, 0, 2); + InsertStaticSequenceList(&static_list, 1, 6); + InsertStaticSequenceList(&static_list, 2, 5); + PrintfStaticSequenceList(static_list); + element_type i = DEFAULTELEM; + DeleteStaticSequenceList(&static_list, 1, &i); + PrintfStaticSequenceList(static_list); + printf("%d", i); + int elem = 65; + int index = LocateStaticSequenceListElement(static_list, elem); + printf("Ԫ%d%dλ\n", elem, index + 1); + return 0;*/ + LinkList list; + InitLinkList(&list); +} \ No newline at end of file diff --git a/Code/sequence_list.h b/Code/sequence_list.h new file mode 100644 index 0000000..81261f6 --- /dev/null +++ b/Code/sequence_list.h @@ -0,0 +1,213 @@ +#include +#include +#include "head.h" + +#pragma warning(disable:6385) +#pragma warning(disable:6386) + +// 静态顺序表 +typedef struct { + element_type data[MAXSIZE]; + int length; +} StaticSequenceList; + +// 动态顺序表 +typedef struct { + element_type *data; + // 已分配的最大容量 + int max_size; + int length; +} DynamicSequenceList; + +// 初始化静态顺序表 +int InitStaticSequenceList(StaticSequenceList* list) { + // 初初始化静态顺序表长度为0 + list->length = 0; + return 0; +} + +// 打印静态顺序表 +int PrintfStaticSequenceList(StaticSequenceList list) { + for (int i = 0; i < list.length; i++) { + printf("第%d个元素值为%d\n", i + 1, list.data[i]); + } + return 0; +} + +// 打印动态顺序表 +int PrintfDynamicSequenceList(DynamicSequenceList list) { + for (int i = 0; i < list.length; i++) { + printf("第%d个元素值为%d\n", i + 1, list.data[i]); + } + return 0; +} + +// 初始化动态顺序表 +int InitDynamicSequenceList(DynamicSequenceList* list) { + // 初初始化动态顺序表长度为0 + list->length = 0; + list->max_size = 0; + // 申请一片连续的存储空间 + element_type* space = (element_type*)malloc(MAXSIZE * sizeof(element_type)); + if (space != NULL) { + list->data = space; + list->max_size = MAXSIZE; + return 0; + } + else { + list->max_size = 0; + printf("InitDynamicSequenceList:初始化失败!\n"); + return 1; + } +} + +// 分配其他地址增长动态顺序表的数据空间长度 +int OtherIncreaseDynamicSequenceList(DynamicSequenceList* list, int len) { + if (len <= 0) { + printf("OtherIncreaseDynamicSequenceList:申请空间应该大于0!\n"); + return 1; + } + // 申请一片连续的存储空间 + int new_length = list->max_size + len; + element_type* space = (element_type*)malloc(new_length * sizeof(element_type)); + if (space != NULL) { + // 建立中间变量 + list->data = space; + int* temp = list->data; + for (int i = 0; i < list->length; i++) { + list->data[i] = temp[i]; + } + list->max_size = new_length; + free(temp); + return 0; + } + else { + printf("OtherIncreaseDynamicSequenceList:重新分配空间失败!\n"); + return 1; + } +} + +// 重新分配地址增长动态顺序表的数据空间长度 +int ReIncreaseDynamicSequenceList(DynamicSequenceList* list, int len) { + if (len <= 0) { + printf("ReIncreaseDynamicSequenceList:申请空间应该大于0!\n"); + return 1; + } + // 申请一片连续的存储空间 + int new_length = list->max_size + len; + element_type* space = (element_type*)realloc(list->data, new_length * sizeof(element_type)); + if (space != NULL) { + list->data = space; + list->max_size += len; + return 0; + } + else { + list->max_size = 0; + list->length = 0; + printf("ReIncreaseDynamicSequenceList:分配其他地址空间失败!\n"); + return 1; + } +} + +// 插入静态顺序表 +int InsertStaticSequenceList(StaticSequenceList* list, int index, element_type elem) { + if (list->length == MAXSIZE) { + printf("InsertStaticSequenceList:静态顺序表空间不足,插入失败!\n"); + return 1; + } + if (index > list->length || index < 0) { + printf("InsertStaticSequenceList:插入索引超过索引范围!\n"); + return 1; + } + for (int i = list->length; i > index; i--) { + list->data[i] = list->data[i - 1]; + } + list->data[index] = elem; + list->length++; + return 0; +} + +// 插入动态顺序表 +int InsertDynamicSequenceList(DynamicSequenceList* list, int index, element_type elem) { + if (list->length == MAXSIZE) { + ReIncreaseDynamicSequenceList(list, 1); + } + if (index > list->length || index < 0) { + printf("InsertDynamicSequenceList:插入索引超过索引范围!\n"); + return 1; + } + for (int i = list->length; i > index; i--) { + list->data[i] = list->data[i - 1]; + } + list->data[index] = elem; + list->length++; + return 0; +} + +// 删除静态顺序表 +int DeleteStaticSequenceList(StaticSequenceList* list, int index, element_type *elem) { + if (index >= list->length || index < 0) { + printf("DeleteStaticSequenceList:删除索引超过索引范围!\n"); + return 1; + } + *elem = list->data[index]; + for (int i = index; i < list->length; i++) { + list->data[i] = list->data[i+1]; + } + list->length--; + return 0; +} + +// 删除动态顺序表 +int DeleteDynamicSequenceList(DynamicSequenceList* list, int index, element_type *elem) { + if (index >= list->length || index < 0) { + printf("DeleteDynamicSequenceList:删除索引超过索引范围!\n"); + return 1; + } + *elem = list->data[index]; + for (int i = index; i < list->length; i++) { + list->data[i] = list->data[i + 1]; + } + list->length--; + return 0; +} + +// 按位获取静态顺序表元素 +element_type GetStaticSequenceListElement(StaticSequenceList list, int index) { + if (index >= list.length || index < 0) { + printf("GetStaticSequenceListElement:查找索引超过索引范围!\n"); + return 1; + } + return list.data[index]; +} + +// 按位获取动态顺序表元素 +element_type GetDynamicSequenceListElement(DynamicSequenceList list, int index) { + if (index >= list.length || index < 0) { + printf("GetDynamicSequenceListElement:查找索引超过索引范围!\n"); + return 1; + } + return list.data[index]; +} + +// 按值获取静态顺序表索引 +int LocateStaticSequenceListElement(StaticSequenceList list, element_type elem) { + for (int i = 0; i < list.length; i++) { + if (list.data[i] == elem) { + return i; + } + } + printf("LocateStaticSequenceListElement:未能定位到对应值的元素!\n"); + return -1; +} + +// 按值获取动态顺序表索引 +int LocateDynamicSequenceListElement(DynamicSequenceList list, element_type elem) { + for (int i = 0; i < list.length; i++) { + if (list.data[i] == elem) { + return i; + } + } + printf("LocateDynamicSequenceListElement:未能定位到对应值的元素!\n"); + return -1; +} \ No newline at end of file diff --git a/Data-Structrue/linear-list.md b/Data-Structrue/linear-list.md index 8d6454c..945a423 100644 --- a/Data-Structrue/linear-list.md +++ b/Data-Structrue/linear-list.md @@ -22,7 +22,14 @@ $L=(a_1,a_2,\cdots,a_i,\cdots,a_n)$,其中$i$表示元素在线性表中的位 把逻辑上相邻的元素存储在物理位置上也相邻的存储单元中,元素之间的关系由存储单元的邻接关系来实现。 -### 定义 +### 顺序表特点 + +1. 随机访问,可以在$O(1)$时间内找到对应元素。 +2. 存储密度高,只用存储数据。 +3. 拓展容量不方便。 +4. 插入删除操作不方便。 + +### 顺序表定义 使用C语言的结构体定义顺序表,使用`typedef`定义一个ElemType表示数据基本类型,并定义最大长度MaxSize: @@ -50,22 +57,16 @@ typedef struct { max_size表示动态顺序表当前可以使用的最大存储空间。 -### 特点 +### 顺序表操作 -1. 随机访问,可以在$O(1)$时间内找到对应元素。 -2. 存储密度高,只用存储数据。 -3. 拓展容量不方便。 -4. 插入删除操作不方便。 - -### 操作 - -#### 初始化 +#### 顺序表初始化 ```c // 初始化静态顺序表 -void InitStaticSequenceList(StaticSequenceList* list) { +int InitStaticSequenceList(StaticSequenceList* list) { // 初初始化静态顺序表长度为0 list->length = 0; + return 0; } ``` @@ -73,39 +74,425 @@ void InitStaticSequenceList(StaticSequenceList* list) { ```c // 初始化动态顺序表 -void InitDynamicSequenceList(DynamicSequenceList* list) { +int InitDynamicSequenceList(DynamicSequenceList* list) { // 初初始化动态顺序表长度为0 list->length = 0; + list->max_size = 0; // 申请一片连续的存储空间 - list->data = (element_type*)malloc(MAXSIZE * sizeof(element_type)); - list->max_size = MAXSIZE; + element_type* space = (element_type*)malloc(MAXSIZE * sizeof(element_type)); + if (space != NULL) { + list->data = space; + list->max_size = MAXSIZE; + return 0; + } + else { + list->max_size = 0; + printf("InitDynamicSequenceList:初始化动态顺序表失败!\n"); + return 1; + } } ``` 动态顺序表不仅需要设置数据长度与最大长度,还得分配数组初始空间。 -#### 增长数据空间长度 +#### 顺序表增长数据空间长度 只有动态顺序表才能增加。 ```c -// 增长动态顺序表的数据空间长度 -void IncreaseDynamicSequenceList(DynamicSequenceList* list, int len) { +// 分配其他地址增长动态顺序表的数据空间长度 +int OtherIncreaseDynamicSequenceList(DynamicSequenceList* list, int len) { + if (len <= 0) { + printf("OtherIncreaseDynamicSequenceList:申请空间应该大于0!\n"); + return 1; + } // 申请一片连续的存储空间 int new_length = list->max_size + len; - element_type* space = (element_type*)realloc(list->data, new_length); + element_type* space = (element_type*)malloc(new_length * sizeof(element_type)); if (space != NULL) { + // 建立中间变量 list->data = space; - list->max_size += len; + int* temp = list->data; + for (int i = 0; i < list->length; i++) { + list->data[i] = temp[i]; + } + list->max_size = new_length; + free(temp); + return 0; } else { - list->max_size = 0; - list->length = 0; - printf("分配空间失败!"); + printf("OtherIncreaseDynamicSequenceList:重新分配地址增长动态顺序表空间失败!\n"); + return 1; } } ``` -#### 插入 +```c +// 重新分配地址增长动态顺序表的数据空间长度 +int ReIncreaseDynamicSequenceList(DynamicSequenceList* list, int len) { + if (len <= 0) { + printf("ReIncreaseDynamicSequenceList:申请空间应该大于0!\n"); + return 1; + } + // 申请一片连续的存储空间 + int new_length = list->max_size + len; + element_type* space = (element_type*)realloc(list->data, new_length * sizeof(element_type)); + if (space != NULL) { + list->data = space; + list->max_size += len; + return 0; + } + else { + list->max_size = 0; + list->length = 0; + printf("ReIncreaseDynamicSequenceList:分配其他地址增长动态顺序表空间失败!\n"); + return 1; + } +} +``` + +#### 顺序表插入 + +倒序移动元素,最后将数据插入对应索引并长度减一。 插入时间复杂度为:$T(n)=O(n)$,空间复杂度为$S(n)=O(1)$。 + +```c +// 插入静态顺序表 +void InsertStaticSequenceList(StaticSequenceList* list, int index, element_type elem) { + if (list->length == MAXSIZE) { + printf("InsertStaticSequenceList:静态顺序表空间不足,插入失败!\n"); + return 1; + } + if (index > list->length || index < 0) { + printf("InsertStaticSequenceList:插入索引超过静态态顺序表索引范围!\n"); + return 1; + } + for (int i = list->length; i > index; i--) { + list->data[i] = list->data[i - 1]; + } + list->data[index] = elem; + list->length++; + return 0; +} +``` + +```c +// 插入动态顺序表 +int InsertDynamicSequenceList(DynamicSequenceList* list, int index, element_type elem) { + if (list->length == MAXSIZE) { + ReIncreaseDynamicSequenceList(list, 1); + } + if (index > list->length || index < 0) { + printf("InsertDynamicSequenceList:插入索引超过动态顺序表索引范围!\n"); + return 1; + } + for (int i = list->length; i > index; i--) { + list->data[i] = list->data[i - 1]; + } + list->data[index] = elem; + list->length++; + return 0; +} +``` + +#### 顺序表删除 + +正序移动元素并长度减一。 + +顺序表的删除时间复杂度为:$T(n)=O(n)$,空间复杂度为$S(n)=O(1)$。 + +```c +// 删除静态顺序表 +int DeleteStaticSequenceList(StaticSequenceList* list, int index, element_type *elem) { + if (index >= list->length || index < 0) { + printf("DeleteStaticSequenceList:删除索引超过静态态顺序表索引范围!\n"); + return 1; + } + *elem = list->data[index]; + for (int i = index; i < list->length; i++) { + list->data[i] = list->data[i+1]; + } + list->length--; + return 0; +} +``` + +```c +// 删除动态顺序表 +int DeleteDynamicSequenceList(DynamicSequenceList* list, int index, element_type *elem) { + if (index >= list->length || index < 0) { + printf("DeleteDynamicSequenceList:删除索引超过动态态顺序表索引范围!\n"); + return 1; + } + *elem = list->data[index]; + for (int i = index; i < list->length; i++) { + list->data[i] = list->data[i + 1]; + } + list->length--; + return 0; +} +``` + +#### 顺序表查找 + +按位查找时间复杂度为$T(n)=O(1)$。 + +```c +// 按位获取静态顺序表元素 +element_type GetStaticSequenceListElement(StaticSequenceList list, int index) { + if (index >= list.length || index < 0) { + printf("GetStaticSequenceListElement:查找索引超过静态顺序表索引范围!\n"); + return 1; + } + return list.data[index]; +} +``` + +```c +// 按位获取动态顺序表元素 +element_type GetDynamicSequenceListElement(DynamicSequenceList list, int index) { + if (index >= list.length || index < 0) { + printf("GetDynamicSequenceListElement:查找索引超过动态态顺序表索引范围!\n"); + return 1; + } + return list.data[index]; +} +``` + +按值查找一般都是找到第一个元素等于指定值的元素,返回其位序,如果没有找到就返回-1。按位查找时间复杂度为$T(n)=O(n)$。 + +```c +// 按值获取静态顺序表索引 +int LocateStaticSequenceListElement(StaticSequenceList list, element_type elem) { + for (int i = 0; i < list.length; i++) { + if (list.data[i] == elem) { + return i; + } + } + printf("LocateStaticSequenceListElement:未能定位到对应值的元素!\n"); + return -1; +} +``` + +```c +// 按值获取动态顺序表索引 +int LocateDynamicSequenceListElement(DynamicSequenceList list, element_type elem) { + for (int i = 0; i < list.length; i++) { + if (list.data[i] == elem) { + return i; + } + } + printf("LocateDynamicSequenceListElement:未能定位到对应值的元素!\n"); + return -1; +} +``` + +## 单链表 + +每个结点只包含一个指针域,也称为线性链表。 + +通常用头指针来标识一个单链表,如单链表L。 + +### 单链表特点 + ++ 不要求大量连续空间,删除和插入方便。 ++ 不可随机存取。 ++ 要花费多余空间存放指针。 + +### 单链表定义 + +使用LinkNode表示一个单链表结点的结构体,而使用LinkList表示一个单链表,其实LinkList是一个指向LinkNode的指针变量。如定义LinkList L等价于LinkNode* L。 + +```c +// 链表结点 +typedef struct { + element_type data; + struct LinkNode* next; +} LinkNode, *LinkList; +``` + +### 单链表操作 + +#### 单链表初始化 + +有带头节点与不带头节点的初始化的区别,带头节点代表第一个结点不存放数据,只是用于标识单链表的开始,但是区别不大,带头结点更好使用。 + +```c +// 初始化无头节点单链表 +int InitLinkListWithoutHead(LinkList list) { + list = NULL; + return 0; +} +``` + +```c +// 初始化有头节点单链表 +int InitLinkListWithHead(LinkList list) { + list = (LinkNode*)malloc(sizeof(LinkNode)); + if (list == NULL) { + return 1; + } + list->next = NULL; + return 0; +} +``` + +#### 单链表插入 + +插入方式一共分为下面几种: + ++ 按位序插入: + + 带头点结。 + + 不带头结点。 ++ 指定结点插入: + + 前插入。 + + 后插入。 + +假定从第一个结点开始就是第0索引的结点。 + +带头结点的单链表头结点就是0号结点,不带头节点的第一个数据结点就是0号结点。 + +带头结点的单链表只能往头结点之后插入,所以插入索引必须从1开始。 + +```c +int InsertLinkListWithHead(LinkList list, int index, element_type elem) { + if (index < 1) { + printf("InsertLinkListWithHead:插入索引值过小!\n"); + return 1; + } + // 定义一个结点指针p指向当前扫描到的结点 + LinkNode* p; + // 定义一个变量i表示当前扫描到的结点的索引号 + int i = 0; + // 将链表头结点指向p,为第0个结点 + p = list; + // 循环遍历到达指定索引号的单链表的结点 + // 条件是当前结点的下一个不为空且索引号到达,所到达的结点一定不是空结点 + while (p->next != NULL && i < index-1) { + p = p->next; + i++; + } + // 如果此时i小于index-1,表示遍历完还没有到达对应的索引 + if (i < index-1) { + printf("InsertLinkListWithHead:插入索引值过大!\n"); + return 1; + } + // 此时i==index-1 + LinkNode* s = (LinkNode*)malloc(sizeof(LinkNode)); + if (s == NULL) { + printf("InsertLinkListWithHead:分配内存失败!\n"); + return 1; + } + s->data = elem; + // 将p原来的后继给新的结点 + s->next = p->next; + p->next = s; + return 0; +} +``` + +不带头结点的单链表可以插入到第一个位置,所以插入所以插入索引可以为0。当插入索引为0时需要特殊处理,其他则基本不变。 + +```c +// 插入无头节点单链表元素 +int InsertLinkListWithoutHead(LinkList list, int index, element_type elem) { + if (index < 0) { + printf("InsertLinkListWithoutHead:插入索引值过小!\n"); + return 1; + } + if (index == 0) { + LinkNode* s = (LinkNode*)malloc(sizeof(LinkNode)); + s->data = elem; + // 将s的后继设为list指针 + s->next = list; + // 将list指针设置为s指针 + list = s; + return 0; + } + // 定义一个结点指针p指向当前扫描到的结点 + LinkNode* p; + // 定义一个变量i表示当前扫描到的结点的索引号 + int i = 0; + // 将链表头结点指向p,为第0个结点 + p = list; + // 循环遍历到达指定索引号的单链表的结点 + // 条件是当前结点的下一个不为空且索引号到达,所到达的结点一定不是空结点 + while (p->next != NULL && i < index - 1) { + p = p->next; + i++; + } + // 如果此时i小于index-1,表示遍历完还没有到达对应的索引 + if (i < index - 1) { + printf("InsertLinkListWithoutHead:插入索引值过大!\n"); + return 1; + } + // 此时i==index-1 + LinkNode* s = (LinkNode*)malloc(sizeof(LinkNode)); + if (s == NULL) { + printf("InsertLinkListWithoutHead:分配内存失败!\n"); + return 1; + } + s->data = elem; + // 将p原来的后继给新的结点 + s->next = p->next; + p->next = s; + return 0; +} +``` + +头插法建立单链表: + ++ 每个结点的插入时间为$O(1)$,设单链表长为n,则总时间复杂度为$O(n)$。 ++ 实现了输入数据的就地逆置。 + +尾插法建立单链表 + ++ 增设尾指针r。 ++ 生成的链表中结点数据与输入数据顺序一致。 ++ 总时间复杂度为$O(n)$。 + +```c +// 后插入单链表元素 +int InsertNextLinkNode(LinkNode* node, element_type elem) { + if (node == NULL) { + return 1; + } + LinkNode* s = (LinkNode*)malloc(sizeof(LinkNode)); + // 如果分配空间失败 + if (s == NULL) { + printf("InsertNextLinkNode:分配内存失败!\n"); + return 1; + } + s->data = elem; + s->next = node->next; + node->next = s; + return 0; +} +``` + +插入有/无头节点单链表元素函数的后面代码可以使用后插入单链表元素函数来替代。 + +使用前插入的方法插入元素,可以使用头指针来得到整个链表信息,从而就能找到链表中的这个结点,但是如果没有头指针那么就无法实现了。且这种遍历的时间复杂度是$O(n)$。 + +还有另一种方式实现前插法,先后插一个元素,把前面结点的数据移动到这个新加的结点,把要新加的数据放在原来的结点,这就实现了后插,虽然地址没有变化,但是从数据上看就是前插,且时间复杂度是$O(1)$。 + +```c +// 前插入单链表元素 +int InsertPriorLinkNode(LinkNode* node, element_type elem) { + if (node == NULL) { + return 1; + } + LinkNode* s = (LinkNode*)malloc(sizeof(LinkNode)); + // 如果分配空间失败 + if (s == NULL) { + printf("InsertPriorLinkNode:分配内存失败!\n"); + return 1; + } + s->next = node->next; + node->next = s; + s->data = node->data; + node->data = elem; + return 0; +} +```