2009年408数据结构程序设计题

本文深入探讨单链表的高效查找策略,特别是在不改变链表的前提下查找倒数第k个结点的方法,包括蛮力法和最优解法,后者仅需一次遍历即可完成查询。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

2009年考察关于单链表的相关知识,本篇给出解题思路并较全面梳理单链表相关知识。

题目

(15分)已知一个带有表头结点的单链表,结点结构为:

假设该链表只给出了头指针list。在不改变链表的前提下,请设计一个尽可能高效的算法:
查找链表中倒数第 k 个位置上的结点(k 为正整数)。
若查找成功,算法输出该结点的 data 域的值,并返回 1;否则,只返回 0。
要求:
⑴ 描述算法的基本设计思想;
⑵ 描述算法的详细实现步骤;
⑶ 根据设计思想和实现步骤,采用程序设计语言描述算法

注意题目所给信息
1.带头结点
2.单链表:不能访问前继节点,只能访问后继节点。
3.未知单链表长度
4.k为正整数,即k>0。不需要做k<=0越界判断。

单链表

单链表(单向链表)数据结构回顾:
单链表是线性表的链式存储。由多个节点组成,每个节点又由数据域和指针域构成。如图:

结点结构

用一个结构体描述节点类型:

struct ListNode {
   
   
  int data;  //节点的数据域,用来存放数值内容 
  struct ListNode *link;  // 节点的指针域,用来指向下一个节点 
};

这里的节点结构内容和题目所给的一致。

头节点

关于头节点一些需要的注意的,做出如下总结梳理
说明:
1.头节点不是链表第一个节点,而是头节点随后紧邻的后继节点。
2.头节点是非必须的,可以不设置。
3.在计算链表长度时,头节点不计入总数。
4.头节点的数据域没有意义。

好处:
1.使链表首个位置的插入删除更加方便,和其他位置一样,不需要涉及到头指针的移动。
2.统一空表和非空表的操作处理。当非空时头指针指向的是首个节点的地址,即*ListNode类型,而对空表处理的时候却是NULL,因此造成空表和非空表操作不一致。

头指针

其实指向某个节点的地址的指针丢失,也会造成这个节点无法访问。特别是头指针,一旦丢失,导致链表最前面的节点(头节点或者是第一个节点)无法访问,从而导致整个链表无法访问,出现内存泄漏等问题。
作用:具有标识作用,故常用头指针冠以链表的名字

单链表基本操作

链表的基本操作如下:

链表的初始化

/*
单链表的初始化
返回一个ListNode指针类型变量,即链表的头指针
*/
struct ListNode* initLinkList(){
   
   
  struct ListNode *head;  //定义头节点
  head = (struct ListNode *)malloc(sizeof(struct ListNode));  //头结点空间申请
  //这里做一个判断,判断头节点是否申请成功
  if(head == NULL){
   
   
    printf("内存不足!申请内存空间失败\n");
  }
  head->link = NULL;  //头节点指向的下一个节点位置置为空
  return head;  //返回头节点地址
}

节点的创建

将创建新节点这个过程封装到一个函数,便于复用。

/*
新创建节点
返回值:新节点地址
*/
struct ListNode* newNode(int data, struct ListNode *link){
   
   
  struct ListNode *newNode;  //定义新节点
  newNode = (struct ListNode*)malloc(sizeof(struct ListNode));  //新结点空间申请
  newNode->data = data;  //新结点数据域初始化
  newNode->link = link;  //新结点指针域初始化
  return newNode;
}

节点的插入

思路:
调用findNodeByIndex函数(查找节点操作),获得第 i-1 节点,然后再进行插入操作。

具体的原理实现如下图所示:

说明:
这里一个数值,以及新节点所在位置来实现单链表中新节点插入操作。
新节点创建在函数内进行,并不是通过真正意义上传入一个节点类型实现插入操作。
时间性能:O(n)

具体步骤:

  1. 首先需要找到插入位置的前一个节点, 也就是图上节点preNode。若找不到,则是越界等问题,返回报错信息。
  2. 然后需要创建新的节点newNode
  3. 插入操作实际上就是把preNode的后继节点改为新节点newNode,然后再把新节点newNode的后继节点改为第 i节点。需要注意顺序,以防出现断链。改动指针操作顺序正如图所示,先①后②。
    代码如下:
    ①:newNode->link = preNode->link;
    ②:preNode->link = newNode;
    对于①表示把新节点newNode的后继节点改为第 i节点。第 i节点的地址通过它的前继节点来寻找,即:preNode->link
    对于②表示把preNode的后继节点改为新节点newNode
/*
插入节点操作
list*:新节点插入所在的链表
index:新节点插入的位置
data:新节点数据域的值
返回值:
0:插入失败
1:插入成功
*/
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值