赞
踩
目录
时间复杂度:O(n) 空间复杂度:O(1)
- // 单链表的结点存储结构
-
- typedef struct LNode{
- ElemType data; // 数据域
- struct LNode *next; // 结点域
- } LNode, *LinkList;
算法实现:
- void Del_x(LinkList L, ElemType x){
- // L为带头结点的链表
- LinkList p = L->next, pre = L, q;
- if (p == NULL)
- {
- printf("链表为空!\n");
- return;
- }
- while(p){
- if (p->data == x) {
- q = p; // q指向要删除的结点
- p = p->next; // p->指向要删除结点的后驱
- pre->next = p; // q的前驱指向q的后驱
- free(q); // 释放q(需要删除的结点)
- }
- else{
- pre = p; // pre向下后移
- p = p->next; // p与pre同步向后移,这两步不能调换顺序
- }
- }
- return;
- }
图解算法:
先看下面这个链表,咱们要删除 x = 2 的结点
L指向头结点
pre开始指向头结点,p指向链表的第一个结点,通过while循环中的 if 语句判断,p->data 2,故pre和q同步后移。
后移后p->data = 2,因此要删除这个结点,即指行while循环里面的 if 语句,q指向要删除的结点,
p指向要删除结点的后驱,pre不要移动。
然后通过free()函数将 q 指向的空间释放,并且pre的后驱指向 p(即pre->next = p),此时链表没有 q指向的结点。
然后再通过 if 语句判断,p->data 2,pre 和 q 同步后移。
然后p->data = 2即要删除这个结点,p的后驱是空指针NULL,故最后 p = NULL,通过free()函数释放此结点,然后pre的后驱指向 p,即 pre->next = NULL。
然后p = NULL,循环结束,链表中无结点数据域等于2的结点,任务完成。
时间复杂度:O(n) 空间复杂度:O(1)
算法实现:
- void Del_x(LinkList L, ElemType x){
- LinkList p = L->next, r = L, q;
- if ( p == NULL)
- {
- printf("链表为空!\n");
- return;
- }
- while(p){
- if (p->data != x){
- r->next = p; // p结点的值不为x,链接到L的尾部
- r = p; // 方便下次链接
- p = p->next;
- }
- else{
- q = p; // 保存要删除的结点
- p = p->next; // 指向要删除结点的后驱,继续扫描
- free(q); // 释放结点
- }
- }
- r->next = NULL; // 插入结束后,尾结点的next域为NULL
- return;
- }
图解算法:
这个算法咱们可以这么理解,类似创建了新链表(在原链表上创建),然后往新链表插入结点的值不为x的结点,用的内存还是原来结点的内存(即指向的内存和原结点的地址一致),并不是新的分配的内存。和实际创建新链表(不在原链表上创建),通过复制结点后插入不同,复制插入的结点的地址不是原结点的地址(即指向的内存地址与原结点不一致),而是新分配的内存。
先看这个链表的初始情况
咱们为了更好的理解,可以将这个链表分为两个链表,一个为L指向头结点的链表,一个为p指向除头结点所有结点组成的链表 。
根据while循环的的 if 语句判断,p所指向的结点并不是要删除的结点,故p指向下一个节点,而刚才p指向的结点被链接到L所指向的链表上。
r->next = p; // p结点的值不为x,链接到L的尾部
现在p指向的是要删除的结点,执行 if 语句的else部分,用q指向它,而p指向要删除结点的后驱。
然后通过free()函数释放q所指向的结点。
此时p指向的结点不是要删除的结点,p后移,p之前的结点链接到L指向的链表。
r->next = p; // p结点的值不为x,链接到L的尾部
此时p指向的是要删除的结点,p向后移,并且q指向此结点。
通过free()函数释放q结点,此时p指向NULL,while循环结束,将L指向的链表最后结点的next指向NULL。
总结来说,就是把结点不是删除结点,就链接到L指向的链表,是要删除的结点通过free()函数释放。
算法思路如下:
算法实现:
1、C++代码实现
- // C++代码 LinkList &L,是一个引用
- void Del_x(LinkList &L, ElemType x){
- // L是不带头结点的链表
- LinkList p;
- if (L == NULL) // 递归出口
- return;
- if (L->data == x){
- p = L; // 删除L,并让L指向下一个结点
- L = L->next;
- free(p);
- Del_x(L, x); // 递归调用
- }
- else // 若L指向的结点不为x
- Del_x(L->next, x); // 递归调用
- return;
- }
-
2、C语言代码实现
- void Del_x(LinkList* head, ElemType x)
- {
- // head为指向不带头结点链表的第一个结点的指针的指针
- // head为二级指针,需要修改内存上保存的指向LinkList的地址
- LinkList p; // 保存要删除的结点地址
- if (*head == NULL)
- return; // 空链表,退出程序
- if ((*head)->data == x) // 判断结点的值是否为x
- {
- p = *head; // 保存要删除的结点
- *head = p->next; // 保存要删除的结点后驱地址
- Del_x(head, x); // 递归函数
- }
- else
- {
- head = &((*head)->next); // 指向下一个结点的地址的地址
- Del_x(head, x);
- }
- }
这个算法要区分结构体指针和指向结构体指针的指针,可以看看我写的博客来了解结构体指针和指向结构体指针的区别。
算法需要一个递归工作栈,深度为O(n),时间复杂度为O(n)。
测试程序:
- #include <stdio.h>
- #include <stdlib.h>
- #include <stdbool.h>
-
- #define FLAG -1
-
- typedef int ElemType;
- typedef struct Node
- {
- ElemType data;
- struct Node* next;
- }LinkNode, * LinkList;
-
- LinkList AddHead2(int flag);
- void ShowLinkList(LinkList head);
- int ListLength(LinkList head);
- bool Insert(LinkList head, ElemType x, int i, int ListLength);
- bool Delete(LinkList head, int i, int ListLength);
- int ShowMeanu();
- //void Del_x(ElemType x, LinkList head);
- void Del_x(LinkList* head, ElemType x);
-
- int main(void)
- {
- int choice;
- LinkList head = (LinkList)malloc(sizeof(LinkNode));
- head->next = NULL;
- while (true)
- {
- choice = ShowMeanu();
- switch (choice)
- {
- case 0: exit(0);
- break;
- case 1: head = AddHead2(FLAG);
- break;
- case 2: ShowLinkList(head);
- break;
- case 3: {
- int i, x;
- printf("请输入你要插入结点的位置:");
- scanf("%d", &i);
- printf("请输入你要插入结点的数据域的值:");
- scanf("%d", &x);
- int length = ListLength(head);
- Insert(head, x, i, length);
- }
- break;
- case 4: {
- int i;
- printf("请输入你要插入结点的位置:");
- scanf("%d", &i);
- Delete(head, i, ListLength(head));
- }
- break;
- case 5: {
- int length;
- length = ListLength(head);
- printf("链表的长度为:%d\n");
- }
- break;
- case 6: {
- int x;
- printf("请输入要删除所有结点为x的值:");
- scanf("%d", &x);
- LinkList p = &(head->next);
- //Del_x(head, x);
- Del_x(p, x);
- }
- break;
- default: printf("请输入恰当的值!!!!\n");
- }
- }
- return 0;
- }
-
- int ShowMeanu()
- {
- int choice;
- printf("欢迎来到链表测试功能!!!!!!\n");
- printf("1.创建单链表 2.显示单链表中的结点\n");
- printf("3.在链表i位置插入节点 4.删除链表第i个结点\n");
- printf("5.单链表的表长 6.删除链表为x的所有结点\n");
- printf("0.退出程序\n");
- printf("请输入你想测试的功能序号:");
- scanf("%d", &choice);
- return choice;
- }
-
- LinkList AddHead2(int flag)
- {
- printf(" 输入 -1 停止创建单链表\n");
- LinkList head, p, q;
- head = (LinkList)malloc(sizeof(LinkNode));
- head->next = NULL;
- p = head;
- ElemType x;
- scanf("%d", &x);
- while (x != flag)
- {
- q = (LinkList)malloc(sizeof(LinkNode));
- q->data = x;
- if (head->next == NULL)
- head->next = q;
- else
- p->next = q;
- p = q;
- scanf("%d", &x);
- }
- if (p != NULL)
- p->next = NULL;
- return head;
- }
-
- void ShowLinkList(LinkList head)
- {
- LinkList p = head->next;
- while (p != NULL)
- {
- printf("%d", p->data);
- p = p->next;
- }
- printf("\n");
- }
-
- int ListLength(LinkList head)
- {
- int len = 0;
- LinkList p = head;
- while (p->next != NULL)
- {
- len++;
- p = p->next;
- }
- return len;
- }
-
- bool Insert(LinkList head, ElemType x, int i, int ListLength)
- {
- LinkList p = head;
- if (i > ListLength || p->next == NULL)
- return false;
- while (--i)
- p = p->next;
- LinkList q = (LinkList)malloc(sizeof(LinkNode));
- q->data = x;
- q->next = p->next;
- p->next = q;
- return true;
- }
-
- bool Delete(LinkList head, int i, int ListLength)
- {
- LinkList p = head;
- if (i > ListLength || p->next == NULL)
- return false;
- while (--i)
- p = p->next;
- LinkList q = p->next;
- p->next = q->next;
- free(q);
- return false;
- }
-
- /*void Del_x(ElemType x, LinkList head)
- {
- LinkList p = head->next, pre = head, q;
- if (p == NULL)
- {
- printf("链表为空\n");
- return;
- }
- while (p)
- {
- if (p->data == x)
- {
- q = p;
- p = q->next;
- pre->next = p;
- free(q);
- }
- else
- {
- pre = p;
- p = p->next;
- }
- }
- return;
- }*/
-
- /*void Del_x(ElemType x, LinkList L) {
- LinkList p = L->next, r = L, q;
- if (p == NULL)
- {
- printf("链表为空!\n");
- return;
- }
- while (p) {
- if (p->data != x) {
- r->next = p; // p结点的值不为x,链接到L的尾部
- r = p; // 方便下次链接
- p = p->next;
- }
- else {
- q = p; // 保存要删除的结点
- p = p->next; // 指向要删除结点的后驱,继续扫描
- free(q); // 释放结点
- }
- }
- r->next = NULL; // 插入结束后,尾结点的next域为NULL
- return;
- }*/
-
- void Del_x(LinkList* head, ElemType x)
- {
- LinkList p;
- if (*head == NULL)
- return;
- if ((*head)->data == x)
- {
- p = *head;
- *head = p->next;
- Del_x(head, x);
- }
- else
- {
- head = &((*head)->next);
- Del_x(head, x);
- }
- }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。