数据结构--单链表的插入&删除

文章详细介绍了单链表的插入和删除操作,包括按位序插入、指定结点前后插入以及按位序删除和删除指定结点。同时,讨论了带头结点和不带头结点链表的区别,并提供了相关的时间复杂度分析。代码示例展示了具体实现过程,强调了不同情况下的处理策略,如在链表末尾删除结点可能需要O(n)的时间复杂度。
摘要由CSDN通过智能技术生成

数据结构–单链表的插入&删除

目标
单链表的插入(位插、前插、后插)
单链表的删除

单链表的插入

按为序插入(带头结点)

ListInsert(&L,i,e):插入操作。在表L中的第i个位置上插入指定元素e。

思路:找到第i-1个结点,将新结点插入其后

代码实现
typedef struct LNode
{
    ElemType data;  
    struct LNode *next; 
}LNode, *LinkList;

bool ListInsert(LinkList &L, int i, ElemType e)
{
    if (i < 1)  return false;

    LNode *p = L; //L指向头结点,头结点是第0个结点(不存数据)
    int j = 0; //当前p指向的是第几个结点
    while (p != NULL && j < i - 1) //循环找到第i-1个结点
    {
        p = p->next;
        j++;
    }
    if (p == NULL)  return false;
    LNode* s = (LNode*)malloc(sizeof(LNode));
    s->next = p->next;
    s->data = e;
    p->next = s;
    return true;
}
时间复杂度

最好时间复杂度 O(1)
最坏时间复杂度 O(1)
平均时间复杂度 O(1)

按位序插入(不带头结点)

思路:找到第i-1个结点,将新结点插入其后

代码实现
typedef struct LNode
{
    ElemType data;  
    struct LNode *next; 
}LNode, *LinkList;


bool ListInsert(LinkList &L, int i, ElemType e)
{
    if (i < 1)  return false;

    if (i == 1) //插入第1个结点的操作与其他结点操作不同
    {
        LNode* s = (LNode*)malloc(sizeof(LNode));
        s->data = e;
        s->next = L;
        L = s;
        return true;
    }

    LNode *p = L; //L指向头结点,头结点是第0个结点(不存数据)
    int j = 0; //当前p指向的是第几个结点
    while (p != NULL && j < i - 1) //循环找到第i-1个结点
    {
        p = p->next;
        j++;
    }
    if (p == NULL)  return false;
    LNode* s = (LNode*)malloc(sizeof(LNode));
    s->next = p->next;
    s->data = e;
    p->next = s;
    return true;
}

结论:
不带头写代码更不方便,推荐用带头结点
注意:考试中带头、不带头都有可能考察,注意审题

指定结点的后插操作

代码实现
typedef struct LNode
{
    ElemType data;
    struct LNode *next;
}LNode, *LinkList;

bool InsertNextNode(LNode* p, ElemType e)
{
    if (p == NULL)  return false;
    LNode* s = (LNode*)malloc(sizeof(LNode));
    if (s == NULL)  return false; // 内存分配失败
    s->data = e;
    s->next = p->next;
    p->next = s;
    return true;
}

指定结点的前插操作

前插操作:在p结点之前插入元素e
bool InsertPriorNode (LNode *p,ElemType e)

方法一:
bool InsertPriorNode (LinkListL L, Node *p,ElemType e)
传入头指针,循环查找p的前驱,再对q后插
时间复杂度:O(n)

方法二 \color{red}方法二 方法二

方法二实现代码
typedef struct LNode
{
    ElemType data;
    struct LNode *next;
}LNode, *LinkList;

bool InsertPriorNode (LNode *p,ElemType e)
{
    if (p == NULL)  return false;

    LNode* s = (LNode*)malloc(sizeof(LNode));
    if (s == NULL)  return false;
    s->next = p->next;
    p->next = s; //新结点s连到p之后
    s->data = p->data; //将p中元素复制到s中
    p->data = e; //p 中元素覆盖为e
    return true;
}

时间复杂度: O(n)

前插操作:在p结点之前插入结点 s
代码实现
bool InsertPriorNode(LNode* p, LNode* s)
{
    if (p == NULL || s == NULL) return false;

    s->next = p->next;
    p->next = s;
    ElemType tmp = p->data;
    p->data = s->data;
    s->data = tmp;
    return true;
}

单链表的删除

按位序删除(带头结点)

ListDelete(&L,i,&e):删除操作。删除表L中第i个位置的元素,并用e返回删除元素的值。

方法:
找到第i-1个结点,将其指针指向第i+1个结点,并释放第i个结点

代码实现
typedef struct LNode
{
    ElemType data;
    struct LNode *next;
}LNode, *LinkList;

bool ListDelete(LinkList &L, int i, ElemType &e)
{
    if (i < 1)  return false;
    LNode *p = L;
    int j = 0;
    while (p != NULL && j < i - 1)
    {
        p = p->next;
        j++;
    }
    if (p == NULL)  return false;
    if (p->next == NULL)    return false; //第i-1个结点之后已无其他结点

    LNode* q = p->next;
    e = q->data; //用e返回元素的值
    p->next = q->next; //将*q结点从链中“断开"
    free(q); //释放结点的存储空间
    return true;
}

时间复杂度:O(n)

删除指定结点p

bool DeleteNode ( LNode *p)

方法1:传入头指针,循环寻找p的前驱结点
时间复杂度O(n)
方法2:偷天换日(类似于结点前插的实现)
时间复杂度O(1)

方法二代码实现
typedef struct LNode
{
    ElemType data;
    struct LNode *next;
}LNode, *LinkList;

bool DeleteNode(LNode* p)
{
    if (p == NULL)  return false;

    LNode* q = p->next; //令q指向*p的后继结点
    p->data = p->next->data; //和后继结点交换数据域
    p->next = q->next; //将*q结点从链中"断开"
    free(q);
    return true;
}

注: \color{red}注: 注:
如果 p 是最后一个结点,只能从表头开始依次寻找 p 的前驱 , 时间复杂度 O ( n ) \color{red} 如果p是最后一个结点,只能从表头开始依次寻找p的前驱,时间复杂度O(n) 如果p是最后一个结点,只能从表头开始依次寻找p的前驱,时间复杂度O(n)

知识点回顾与重要考点

  • 7
    点赞
  • 51
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
单链表插入操作是将一个新的节点插入链表中的指定位置。具体实现步骤如下: 1. 创建一个新的节点,命名为new_node,并设置其数据域为待插入的元素值; 2. 找到插入位置的前一个节点,可以从头结点开始遍历链表,直到找到插入位置的前一个节点,或者链表已经遍历到末尾; 3. 将new_node节点的next指针指向插入位置的后一个节点; 4. 将插入位置的前一个节点的next指针指向new_node节点。 下面是单链表插入操作的示例代码实现: ```c #include <stdio.h> #include <stdlib.h> // 定义单链表节点结构体 typedef struct ListNode { int val; struct ListNode *next; } ListNode; // 在单链表的指定位置插入一个新的元素 void insert(ListNode* head, int pos, int val) { // 创建新的节点 ListNode* new_node = (ListNode*)malloc(sizeof(ListNode)); new_node->val = val; new_node->next = NULL; // 找到插入位置的前一个节点 ListNode* pre = head; for (int i = 0; i < pos - 1 && pre != NULL; i++) { pre = pre->next; } if (pre == NULL) { printf("Insert position is invalid!\n"); return; } // 插入新的节点 new_node->next = pre->next; pre->next = new_node; } // 打印单链表 void printList(ListNode* head) { ListNode* p = head->next; while (p != NULL) { printf("%d ", p->val); p = p->next; } printf("\n"); } // 测试单链表插入操作 int main() { // 创建头结点 ListNode* head = (ListNode*)malloc(sizeof(ListNode)); head->next = NULL; // 插入元素 insert(head, 1, 1); insert(head, 2, 2); insert(head, 3, 3); insert(head, 4, 4); printList(head); return 0; } ``` 输出结果为:1 2 3 4
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Joanh_Lan

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值