From 09f80d310c910761c6d8c61bbc6d741e6553365c Mon Sep 17 00:00:00 2001 From: Didnelpsun <2675350965@qq.com> Date: Sun, 18 Apr 2021 23:47:07 +0800 Subject: [PATCH] =?UTF-8?q?=E6=9B=B4=E6=96=B0=E5=8D=95=E9=93=BE=E8=A1=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Code/link_list.h | 182 ++++++++++++++++++++++++++++++++ Code/sequence_list.h | 12 +-- Data-Structrue/linear-list.md | 188 +++++++++++++++++++++++++++++++++- 3 files changed, 374 insertions(+), 8 deletions(-) diff --git a/Code/link_list.h b/Code/link_list.h index b75ae55..fefb0c0 100644 --- a/Code/link_list.h +++ b/Code/link_list.h @@ -158,4 +158,186 @@ int InsertPriorLinkNode(LinkNode* node, element_type elem) { s->data = node->data; node->data = elem; return 0; +} + +// 删除有头节点单链表元素 +int DeleteLinkListWithHead(LinkList list, int index, element_type *elem) { + if (index < 1) { + printf("DeleteLinkListWithHead:删除索引值过小!\n"); + return 1; + } + // p指向当前扫描的结点 + LinkNode* p; + // i表示当前指向的是第几个结点 + int i = 0; + // 指向头结点 + p = list; + while (p != NULL && i < index - 1) { + p = p->next; + i++; + } + if (p == NULL || p->next == NULL) { + printf("DeleteLinkListWithHead:删除索引值过大!\n"); + return 1; + } + // q指向被删除的结点 + LinkNode* q = p->next; + // 获取删除的元素数据 + *elem = q->data; + // 将q结点从链表中断开 + p->next = q->next; + free(q); + return 0; +} + +// 删除无头节点单链表元素 +int DeleteLinkListWithHead(LinkList list, int index, element_type* elem) { + if (index < 0) { + printf("DeleteLinkListWithHead:删除索引值过小!\n"); + return 1; + } + // p指向当前扫描的结点 + LinkNode* p; + // i表示当前指向的是第几个结点 + int i = 0; + // 指向头结点 + p = list; + // 如果删除第一个第0号结点 + if (index == 0) { + list = p->next; + free(p); + return 0; + } + while (p != NULL && i < index - 1) { + p = p->next; + i++; + } + if (p == NULL || p->next == NULL) { + printf("DeleteLinkListWithHead:删除索引值过大!\n"); + return 1; + } + // q指向被删除的结点 + LinkNode* q = p->next; + // 获取删除的元素数据 + *elem = q->data; + // 将q结点从链表中断开 + p->next = q->next; + free(q); + return 0; +} + +// 删除单链表元素 +int DeleteLinkNode(LinkNode* node) { + if (node == NULL) { + printf("DeleteLinkNode:本结点是空结点无法删除!"); + return 1; + } + // 如果该结点为最后一个结点,无法找到前驱结点,无法操作 + if (node->next = NULL) { + printf("DeleteLinkNode:后继结点为空无法操作!"); + return 1; + } + // 指向后继结点 + LinkNode* p = node->next; + // 交换数据 + node->data = p->data; + // 断开结点 + node->next = p->next; + free(p); + return 0; +} + +// 按位查找单链表元素 +element_type GetLinkListElement(LinkList list, int index) { + if (index < 0) { + printf("GetLinkListElement:查找索引值过小!\n"); + return NULL; + } + // 定义一个结点指针p指向当前扫描到的结点 + LinkNode* p; + // 定义一个变量i表示当前扫描到的结点的索引号 + int i = 0; + // 将链表头结点指向p,为第0个结点 + p = list; + // 循环遍历到达指定索引号的单链表的结点 + // 条件是当前结点的下一个不为空且索引号到达,所到达的结点一定不是空结点 + while (p->next != NULL && i < index) { + p = p->next; + i++; + } + // 如果查找索引大于当前扫描索引 + if (i < index) { + printf("GetLinkListElement:查找索引值过大!\n"); + return NULL; + } + return p->data; +} + +// 按位查找单链表结点 +LinkNode* GetLinkListNode(LinkList list, int index) { + if (index < 0) { + printf("GetLinkListNode:查找索引值过小!\n"); + return NULL; + } + // 定义一个结点指针p指向当前扫描到的结点 + LinkNode* p; + // 定义一个变量i表示当前扫描到的结点的索引号 + int i = 0; + // 将链表头结点指向p,为第0个结点 + p = list; + // 循环遍历到达指定索引号的单链表的结点 + // 条件是当前结点的下一个不为空且索引号到达,所到达的结点一定不是空结点 + while (p->next != NULL && i < index) { + p = p->next; + i++; + } + // 如果查找索引大于当前扫描索引 + if (i < index) { + printf("GetLinkListNode:查找索引值过大!\n"); + } + // 如果索引值过大,其p也会指向最后一个NULL,所以返回值都是一样为NULL,不需要单独处理 + return p; +} + + +// 按值查找单链表结点 +LinkNode* LocateLinkListNode(LinkList list, element_type elem) { + LinkNode* p = list; + while (p != NULL && p->data != elem) { + p = p->next; + } + return p; +} + +// 求链表长度 +int GetLength(LinkList list) { + int len = 0; + LinkNode* p = list; + while (p->next != NULL) { + p = p->next; + len++; + } + return len; +} + +// 后插建立带头节点单链表 +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++; + } } \ No newline at end of file diff --git a/Code/sequence_list.h b/Code/sequence_list.h index 81261f6..7bb3562 100644 --- a/Code/sequence_list.h +++ b/Code/sequence_list.h @@ -172,25 +172,25 @@ int DeleteDynamicSequenceList(DynamicSequenceList* list, int index, element_type return 0; } -// 按位获取静态顺序表元素 +// 按位查找静态顺序表元素 element_type GetStaticSequenceListElement(StaticSequenceList list, int index) { if (index >= list.length || index < 0) { printf("GetStaticSequenceListElement:查找索引超过索引范围!\n"); - return 1; + return NULL; } return list.data[index]; } -// 按位获取动态顺序表元素 +// 按位查找动态顺序表元素 element_type GetDynamicSequenceListElement(DynamicSequenceList list, int index) { if (index >= list.length || index < 0) { printf("GetDynamicSequenceListElement:查找索引超过索引范围!\n"); - return 1; + return NULL; } return list.data[index]; } -// 按值获取静态顺序表索引 +// 按值查找静态顺序表索引 int LocateStaticSequenceListElement(StaticSequenceList list, element_type elem) { for (int i = 0; i < list.length; i++) { if (list.data[i] == elem) { @@ -201,7 +201,7 @@ int LocateStaticSequenceListElement(StaticSequenceList list, element_type elem) return -1; } -// 按值获取动态顺序表索引 +// 按值查找动态顺序表索引 int LocateDynamicSequenceListElement(DynamicSequenceList list, element_type elem) { for (int i = 0; i < list.length; i++) { if (list.data[i] == elem) { diff --git a/Data-Structrue/linear-list.md b/Data-Structrue/linear-list.md index 945a423..6614313 100644 --- a/Data-Structrue/linear-list.md +++ b/Data-Structrue/linear-list.md @@ -243,7 +243,7 @@ int DeleteDynamicSequenceList(DynamicSequenceList* list, int index, element_type element_type GetStaticSequenceListElement(StaticSequenceList list, int index) { if (index >= list.length || index < 0) { printf("GetStaticSequenceListElement:查找索引超过静态顺序表索引范围!\n"); - return 1; + return NULL; } return list.data[index]; } @@ -254,7 +254,7 @@ element_type GetStaticSequenceListElement(StaticSequenceList list, int index) { element_type GetDynamicSequenceListElement(DynamicSequenceList list, int index) { if (index >= list.length || index < 0) { printf("GetDynamicSequenceListElement:查找索引超过动态态顺序表索引范围!\n"); - return 1; + return NULL; } return list.data[index]; } @@ -496,3 +496,187 @@ int InsertPriorLinkNode(LinkNode* node, element_type elem) { return 0; } ``` + +#### 单链表删除 + +基本的方式和插入类似,都是转移next结点。 + +带头结点的也只能删除从1开始的结点,0的头结点不能删除。 + +时间复杂度为$O(n)$。 + +```c +// 删除有头节点单链表元素 +int DeleteLinkListWithHead(LinkList list, int index, element_type *elem) { + if (index < 1) { + printf("DeleteLinkListWithHead:删除索引值过小!\n"); + return 1; + } + // p指向当前扫描的结点 + LinkNode* p; + // i表示当前指向的是第几个结点 + int i = 0; + // 指向头结点 + p = list; + while (p != NULL && i < index - 1) { + p = p->next; + i++; + } + if (p == NULL || p->next == NULL) { + printf("DeleteLinkListWithHead:删除索引值过大!\n"); + return 1; + } + // q指向被删除的结点 + LinkNode* q = p->next; + // 获取删除的元素数据 + *elem = q->data; + // 将q结点从链表中断开 + p->next = q->next; + free(q); + return 0; +} +``` + +无头结点需要额外处理第一个结点 + +```c +// 删除无头节点单链表元素 +int DeleteLinkListWithHead(LinkList list, int index, element_type* elem) { + if (index < 0) { + printf("DeleteLinkListWithHead:删除索引值过小!\n"); + return 1; + } + // p指向当前扫描的结点 + LinkNode* p; + // i表示当前指向的是第几个结点 + int i = 0; + // 指向头结点 + p = list; + // 如果删除第一个第0号结点 + if (index == 0) { + list = p->next; + free(p); + return 0; + } + while (p != NULL && i < index - 1) { + p = p->next; + i++; + } + if (p == NULL || p->next == NULL) { + printf("DeleteLinkListWithHead:删除索引值过大!\n"); + return 1; + } + // q指向被删除的结点 + LinkNode* q = p->next; + // 获取删除的元素数据 + *elem = q->data; + // 将q结点从链表中断开 + p->next = q->next; + free(q); + return 0; +} +``` + +如果删除指定结点而不知道其前驱,也可以使用之前前插结点的方式,把该结点后继的结点的数据复制到本结点上,然后把后继结点删除,就相当于删除了本结点。时间复杂度为$O(1)$。 + +```c +// 删除单链表元素 +int DeleteLinkNode(LinkNode* node) { + if (node == NULL) { + printf("DeleteLinkNode:本结点是空结点无法删除!"); + return 1; + } + // 如果该结点为最后一个结点,无法找到前驱结点,无法操作 + if (node->next = NULL) { + printf("DeleteLinkNode:后继结点为空无法操作!"); + return 1; + } + // 指向后继结点 + LinkNode* p = node->next; + // 交换数据 + node->data = p->data; + // 断开结点 + node->next = p->next; + free(p); + return 0; +} +``` + +所以单链表还是不算方便。 + +#### 单链表查找 + +按位查找时间复杂度为$O(n)$。 + +```c +// 按位查找单链表元素 +element_type GetLinkListElement(LinkList list, int index) { + if (index < 0) { + printf("GetLinkListElement:查找索引值过小!\n"); + return NULL; + } + // 定义一个结点指针p指向当前扫描到的结点 + LinkNode* p; + // 定义一个变量i表示当前扫描到的结点的索引号 + int i = 0; + // 将链表头结点指向p,为第0个结点 + p = list; + // 循环遍历到达指定索引号的单链表的结点 + // 条件是当前结点的下一个不为空且索引号到达,所到达的结点一定不是空结点 + while (p->next != NULL && i < index) { + p = p->next; + i++; + } + // 如果查找索引大于当前扫描索引 + if (i < index) { + printf("GetLinkListElement:查找索引值过大!\n"); + return NULL; + } + return p->data; +} +``` + +```c +// 按位查找单链表结点 +LinkNode* GetLinkListNode(LinkList list, int index) { + if (index < 0) { + printf("GetLinkListNode:查找索引值过小!\n"); + return NULL; + } + // 定义一个结点指针p指向当前扫描到的结点 + LinkNode* p; + // 定义一个变量i表示当前扫描到的结点的索引号 + int i = 0; + // 将链表头结点指向p,为第0个结点 + p = list; + // 循环遍历到达指定索引号的单链表的结点 + // 条件是当前结点的下一个不为空且索引号到达,所到达的结点一定不是空结点 + while (p->next != NULL && i < index) { + p = p->next; + i++; + } + // 如果查找索引大于当前扫描索引 + if (i < index) { + printf("GetLinkListNode:查找索引值过大!\n"); + } + // 如果索引值过大,其p也会指向最后一个NULL,所以返回值都是一样为NULL,不需要单独处理 + return p; +} +``` + +这样插入元素函数InsertLinkListWithHead只用`GetLinkListNode(list,i-1)`和`InsertNextLinkNode(p,elem)`两个函数完成。 + +```c +// 按值查找单链表结点 +LinkNode* LocateLinkListNode(LinkList list, element_type elem) { + LinkNode* p = list; + while (p != NULL && p->data != elem) { + p = p->next; + } + return p; +} +``` + +#### 单链表建立 + +可以使用尾插法建立单链表,从后面不断插入元素。 \ No newline at end of file