第3章线性表:单链表的创建方法和单链表例题

6. 前插法创建单链表

前插法,就是将新结点逐个插入到链表的头部,即头结点后面(首元结点前面),由此创建链表(如图 3.4.8 所示)。

在这里插入图片描述

图 3.4.8 前插法创建单链表

【算法步骤】

  1. 初始化空链表
    • 创建头结点,并初始化指针域为 NULL
    • 检查内存分配是否成功(增强鲁棒性)。
  2. 循环插入元素:逆序输入 n 个元素,每次执行:
    a. 动态生成新结点 *s,检查分配是否成功。
    b. 读取元素值到 s->data(可扩展为从任意数据源输入)。
    c. 将新结点插入头结点之后(前插法)。

【算法描述】

Status CreateList_H(LinkList *L, int n) {
    // 前插法创建带头结点的单链表,逆序输入 n 个元素
    if (n <= 0) return ERROR;  // 检查元素个数合法性

    *L = (LNode*)malloc(sizeof(LNode));  // 创建头结点
    if (!*L) return ERROR;     // 内存分配失败检查
    (*L)->next = NULL;         //创建带头结点的空链表

    for (int i = 0; i < n; ++i) {
        LNode *s = (LNode*)malloc(sizeof(LNode));
        if (!s) {
            // 内存分配失败时,清理已创建的链表
            while ((*L)->next) {
                LNode *temp = (*L)->next;
                (*L)->next = temp->next;
                free(temp);
            }
            free(*L);
            *L = NULL;
            return ERROR;
        }

        scanf("%d", &s->data);  // 输入元素值(假设为整型)
        s->next = (*L)->next;   // 新结点指向原首结点
        (*L)->next = s;         // 头结点指向新结点
    }

    return OK;
}

【算法分析】

  1. 时间复杂度:每次结点创建与插入操作均为 O(1)O(1)O(1) ,循环 n 次,总复杂度 O(n)O(n)O(n)
  2. 空间复杂度:除头结点外,需额外分配 n 个结点(插入的结点),复杂度 O(n)O(n)O(n)

7. 后插法创建单链表

后插法是通过将新结点逐个插入到链表的尾部来创建链表。同前插法一样,每次申请一个新结点,读入相应的数据元素值。不同的是,为了使新结点能够插入到表尾,需要增加一个尾指针 r 指向链表的尾结点(如图 3.4.9 所示)。

在这里插入图片描述

图 3.4.9 后插法创建单链表

【算法步骤】

  1. 初始化阶段

    • 创建头结点并初始化指针域为 NULL
    • 检查头结点是否分配成功
    • 初始化尾指针 r 指向头结点
  2. 循环插入阶段

    • 正序输入 n 个元素,每次执行:
      a. 生成一个新结点 *s
      b. 输入元素值赋给新结点 *s 的数据域;

      c. 将新结点 *s 插入到尾结点 *r 之后;

      d. 尾指针 r 指向新的尾结点 *s

【算法描述】

Status CreateList_R(LinkList *L, int n) {
    // 后插法创建带头结点单链表,正序输入n个元素
    if (n <= 0) return ERROR;  // 参数合法性检查

    *L = (LNode*)malloc(sizeof(LNode));
    if (!*L) return ERROR;     // 头结点分配失败
    (*L)->next = NULL;
    LNode *r = *L;             // 尾指针初始化

    for (int i = 0; i < n; ++i) {
        LNode *s = (LNode*)malloc(sizeof(LNode));
        if (!s) {
            // 分配失败时清理已创建链表
            while ((*L)->next) {
                LNode *temp = (*L)->next;
                (*L)->next = temp->next;
                free(temp);
            }
            free(*L);
            *L = NULL;
            return ERROR;
        }

        scanf("%d", &s->data);  // 输入元素值(假设为整型)
        s->next = NULL;
        r->next = s;    // 链接新结点
        r = s;          // 更新尾指针
    }

    return OK;
}

【算法分析】

  • 时间复杂度: O(n)O(n)O(n)
  • 空间复杂度:O(n)O(n)O(n)

例 3.4.3 线性表L在( )情况下适用于使用链式结构实现。

A. 需经常修改L中的结点值\qquad B. 需不断对L进行删除插入

C. L中含有大量的结点 \qquad D.L中结点结构复杂

【解】

  • 选项 A,经常修改结点的值,即需要查找到该结点,因此顺序表更适合。
  • 选项 B,链表更适合于不断进行删除和插入操作,因为顺序表对于这些操作要移动元素,时间复杂度是 O(n)O(n)O(n) ;链表不需要,只需要修改指针即可,时间复杂度是 O(1)O(1)O(1)
  • 选项 C、D,线性表中元素数量的多少和复杂度的高低,不是选择顺序表还是链表的依据。

本题答案:B

例 3.4.4 在单链表中,要将 s 所指结点插入到 p 所指结点之后,其语句应为( )。

A. s->next = p + 1; p->next = s;

B. (*p).next = s; (*s).next = (*p).next;

C. s->next = p->next; p->next = s->next;

D. s->next = p->next; p->next = s;

【解】

将新结点插入到 p 所指结点之后,其插入语句是 s->next = p->next; p->next = s;

本题答案:D

例 3.4.5 在一个长度为 n(n>1)n(n>1)n(n>1) 的带头结点的单链表 h 上,另设有尾指针 r (指向尾结点),以下执行操作与链表的长度有关的是( )。

A. 删除单链表中的首结点

B. 删除单链表中的尾结点

C. 在单链表首结点前插入一个新结点

D. 在单链表尾结点后插入一个新结点

【解】

根据题目叙述可知单链表有头指针和尾指针,如下图所示。

在这里插入图片描述

选项 A :删除单链表中的首元结点,过程如下:

LinkList *p = h->next;
h->next = p->next;
free(p);

选项 B:删除单链表的尾结点,过程如下:

LinkList *p = h;
while(p->next != r) //查找尾结点的前驱结点
    p = p->next;
p->next = NULL;
free(r);
r = p;

选项 C:在首元结点之前插入一个新结点,过程如下:

//假设插入 *s 结点
s->next = h->next;
h->next = s;

选项 D:在尾节点后插入一个新结点,过程如下:

//假设插入 *s 结点
r->next = s;
s->next = NULL;
r = s;

本题答案:B

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

CS创新实验室

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

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

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

打赏作者

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

抵扣说明:

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

余额充值