`
isiqi
  • 浏览: 16707109 次
  • 性别: Icon_minigender_1
  • 来自: 济南
社区版块
存档分类
最新评论

单向链表的几道题

阅读更多

---------------------------------------------------------------------------

1. 转置单向链表 (也就是反序,注意链表的边界条件并考虑空链表)。

#include <stddef.h>

struct listtype
{
int data;
struct listtype * next;
};

typedef struct listtype * list;

/* Reverse the singly linked list *psll. */
void reverse_singly_linked_list(list * psll)
{
list h = NULL;
list p = *psll;

if (!psll || !*psll)
{
return;
}

while (p)
{
list tmp = p;
p = p->next;
tmp->next = h;
h = tmp;
}

*psll = h;
}

---------------------------------------------------------------------------

2. 在链表里如何发现循环链接?

#include <stddef.h>

struct listtype
{
int data;
struct listtype * next;
};

typedef struct listtype * list;

/* Check that whether there is loop in the singly linked list sll or not. */
int find_circle(list sll)
{
list fast = sll;
list slow = sll;

if (NULL == fast)
{
return -1;
}

while (fast && fast->next)
{
fast = fast->next->next;
slow = slow->next;

if (fast == slow)
{
return 1;
}
}

return 0;
}


参考:
http://ostermiller.org/find_loop_singly_linked_list.html

---------------------------------------------------------------------------

3. 找到单向链表中间那个元素,如果有两个则取前面一个。

#include <stddef.h>

struct listtype
{
int data;
struct listtype * next;
};

typedef struct listtype * list;

/* Find the middle element of the singly linked list sll. */
list find_middle(list sll)
{
list slow = sll;
list fast = sll;

if (NULL == fast)
{
return NULL;
}

while (1)
{
if (NULL == fast->next || NULL == fast->next->next)
{
return slow;
}

slow = slow->next;
fast = fast->next->next;

/* Prevent that there is a loop in the linked list. */
if (fast == slow)
{
return NULL;
}
}
}

---------------------------------------------------------------------------

4. 删除单链表的倒数第 m 个元素。
给定一个单向链表 (长度未知),请设计一个既节省时间又节省空间的算法来找出该链表中的倒数第 m 个元素。实现这个算法,并为可能出现的特例情况安排好处理措施。

#include <stddef.h>

struct listtype
{
int data;
struct listtype * next;
};

typedef struct listtype * list;

/* Find the mth element of the singly linked list sll from the end. */
list find_the_mth_element_from_end(list sll, int m)
{
list fast = sll; /* Used for loop detecting. */
list ahead = sll;
list after = sll;

if (NULL == ahead || m <= 0)
{
return NULL;
}

while (m--)
{
if (NULL == ahead)
{
return NULL;
}
ahead = ahead->next;

if (fast && fast->next)
{
fast = fast->next->next;
if (fast == ahead)
{
return NULL;
}
}
}

while (1)
{
if (NULL == ahead)
{
return after;
}
ahead = ahead->next;
after = after->next;

if (fast && fast->next)
{
fast = fast->next->next;
if (fast == ahead)
{
return NULL;
}
}
}
}

---------------------------------------------------------------------------

5. 给定一个单向链表的头指针,要求找出该链表循环部分的第一个节点。如果该链表不是循环链表,则返回空指针。例如给定下面的链表:
0 -> 1 -> 2 -> 3 -> 4 -> 5 -> 6 -> 7 -> 8 -> (3) 循环
就应该返回结点 3 的指针。请优化时间和空间。

解法一:
一次遍历,把地址存入 hash 表就行了,第一次出现重复的地址就是需要的解。
时间复杂度 O(n),空间复杂度 O(n)。

解法二:
把链表当做有向图,进行深度优先遍历,第一个回退边指向的节点即是需要的解。
时间复杂度 O(n),空间复杂度 O(n)。

解法三:
首先根据链表创建一个逆序的链表。如下:
原始:1->2->3->4->5->6->7->8->(3)
逆序:1->2->3->8->7->6->5->4->(3)
然后分别从两个链表头指针开始,找到 next 指针不一样的那个节点就是最终目标了。
时间复杂度 O(n),空间复杂度 O(n)。

解法四:
用两个步长分别为 1 和 2 的指针前进,第一次相遇之后再前进,第二次相遇时停止。记下从第一次相遇到第二次相遇,步长为 1 的指针走过的步数 S,则 S 为环的长度。然后用两个指针,一个在链头,一个走到链头后第 S 个位置上,同时以步长为 1 前进,判断两个指针是否相等,如果是就是环的起始位置了。
时间复杂度 O(n),空间复杂度 O(1)。

解法五:(跟解法四的思想差不多,优于解法四,因为常数因子小)
用两个步长分别为 1 和 2 的指针前进,第一次相遇之后,令其中一个指针指向链表头。然后,令两个指针步长都为 1,同时前进,相遇时停止。该节点就是环的起始位置。
时间复杂度 O(n),空间复杂度 O(1)。

下面给出解法五的 C 实现。

#include <stddef.h>

struct listtype
{
int data;
struct listtype * next;
};

typedef struct listtype * list;

/*
* Find the head node of the loop in the singly linked list sll.
* If there is not a loop in sll, NULL is return.
*/
list find_head_of_loop(list sll)
{
list slow = sll;
list fast = sll;

if (NULL == fast)
{
return NULL;
}

while (1)
{
if (NULL == fast->next || NULL == fast->next->next)
{
return NULL;
}

slow = slow->next;
fast = fast->next->next;

if (fast == slow)
{
slow = sll;
break;
}
}

while (1)
{
slow = slow->next;
fast = fast->next;

if (fast == slow)
{
return fast;
}
}
}


参考:
http://www.chinaunix.net/jh/23/896018.html

---------------------------------------------------------------------------

6. 给定一个单向链表的结点,要求在常数时间里删除该结点。

常数时间删除结点肯定不行,不过可以用假删除,就是把要删除节点的值用要删除节点的下一个节点值覆盖,然后删除下一个节点 (要求该节点的下一个节点不能是空) :
p->data = p->next->data;
temp = p->next;
p->next = temp->next;
free(temp);

---------------------------------------------------------------------------

分享到:
评论

相关推荐

    C#单向链表的实现

    压缩包中的"Ex17_01"可能包含示例代码或练习题,你可以通过查看这些内容进一步加深对C#单向链表实现的理解。实践是学习编程的最佳途径,尝试编写和修改链表操作的代码,将帮助你巩固理论知识并提升编程技能。

    C++单向链表的实现

    C++进阶学习——单向链表的实现,相关教程链接如下: http://blog.csdn.net/tennysonsky/article/details/49685199

    单向链表(一) 结构体、创建链表、遍历链表

    单向链表是一种基本的数据结构,它在计算机科学和编程中有着广泛的应用。与数组不同,链表中的元素不是在内存中连续存储的,而是通过指针连接起来。本篇文章将深入探讨单向链表的基本概念,包括其结构体定义、如何...

    Kotlin 写单向链表题

    单向链表是一种基本的数据结构,它由一系列节点组成,每个节点包含数据和指向下一个节点的引用。在Kotlin中实现单向链表,我们需要理解链表的基本操作,包括创建链表、添加元素、删除元素以及遍历链表。下面我们将...

    C语言实现带头结点的单向链表的基本操作

    本文详细介绍了使用C语言实现带头结点的单向链表的基本操作,包括链表的创建、输出、插入元素和删除元素,以及单向链表的逆序连接和两个有序线性表的归并。 一、链表的创建 链表的创建是指在内存中分配一个结点,...

    C语言链表相关面试题.zip

    链表的种类主要有单向链表、双向链表和循环链表。单向链表中的节点只包含一个指向下一个节点的指针;双向链表中的节点包含两个指针,一个指向前一个节点,另一个指向下一个节点;循环链表则是首尾相接的链表,形成一...

    链表面试题总结

    - **单向链表**:每个节点只包含一个指向后继节点的指针。 - **双向链表**:每个节点包含两个指针,一个指向前驱节点,另一个指向后继节点。 - **循环链表**:最后一个节点的指针不是指向`NULL`,而是返回到链表的...

    c语言大作业--链表实现学生成绩管理

    本程序是用C语言实现的简单学生成绩管理,用到的主要知识点是链表,涉及到链表的建立,插入,节点的删除,排序等几乎所有的链表常用操作.模块强,可以根据需要自行裁减,原创作品!

    链表填空题(打印)1

    链表分为单向链表、双向链表和循环链表等类型。 1. **输出链表所有结点信息**: 在题目给出的`printlist`函数中,用于遍历链表并打印每个节点的信息。`while`循环条件是`p != NULL`,确保在遍历到链表末尾时停止。...

    数据结构—刘小晶—例2.7-用链表结构写的学生成绩管理系统

    在本主题中,我们将深入探讨如何使用链表结构来实现一个学生成绩管理系统。这个系统由数据结构专家刘小晶教授举例讲解,旨在帮助我们理解数据结构在实际问题中的应用,特别是链表这一核心概念。链表是一种非连续、非...

    华为机试 高级题 链表的整合

    给你一个链表,节点有值域,计数器(表示值出现的次数,初始化为1),指针域,节点的值有重复的,去除重复的值,修改相应节点的计数器。这样做的好处就是节省的很多存储空间。 对即将参加华为机考的同学有非常大的帮助...

    约瑟夫环单循环链表C语言实现

    单向循环链表是一种特殊的线性表存储结构,其中每个节点包含一个指向下一个节点的指针,最后一个节点的指针指向链表的头节点,形成一个闭环。在约瑟夫环问题中,单向循环链表非常适合模拟游戏参与者围成一圈的情形。...

    链表查找倒数第K个数

    链表功能的一个扩展延伸,查找倒数第K个元素,是某年考研题

    算法大全-面试题-链表-栈-二叉树-数据结构

    链表分为单向链表、双向链表和循环链表等类型,它们各有优缺点,如单向链表插入和删除操作相对简便,但访问元素不如数组直接。 栈是一种后进先出(LIFO)的数据结构,常被比喻为一个堆叠的盘子。栈的操作主要包括压...

    华为OD机试 - 单向链表中间节点(Java & JS & Python & C & C++).html

    华为OD机试 - 单向链表中间节点(Java & JS & Python & C & C++).html付费专栏内容,免费下载,多种语言解法

    C语言链表类题目

    值得注意的是,题目中还提供了一个错误的版本包含了 `struct Student *pre` 成员,这实际上不是必需的,因为这是单向链表,无需维护前一个节点的信息。 ##### 创建链表 链表的创建主要涉及内存分配和节点之间的链接...

    数据结构-程序填空题.doc

    在上述题目中,我们看到两个关于创建单向链表的算法,以及链表操作的问题,包括删除和队列操作。 1. 尾插法建立单向链表: 在`create1`函数中,我们需要创建一个带头结点的单向链表,其中节点按顺序插入。填空部分...

    C语言写函数建立一个有三名学生数据的单项动态链表

    单项动态链表(也称为单向链表)是其中一种类型,每个节点只包含一个指向后继节点的链接。 #### 二、题目背景与要求 本题要求用C语言编写程序来创建一个包含三名学生数据的单项动态链表,并提供了三种不同的实现...

    链表练习题(修正)1

    在本题中,我们关注的是单向链表,并探讨了四种基本操作:创建链表、尾插法插入节点、首插法插入节点以及显示链表中的所有数据节点。 1. **插入操作**: 函数`insert`实现了将指定节点插入已排序链表的功能,保持...

    单向链表的补充完全版,具有更多可调用的基本函数

    题:第一,只有头指针,没有尾指针。如要在表尾插入结点,则效率很低。第二,求表长 要从表头找到表尾效率也很低。第三,基本操作函数太少。c2-5.h 是从实际应用角度出发 重新定义的线性链表类型,LinkList 类型增加...

Global site tag (gtag.js) - Google Analytics