`
qiemengdao
  • 浏览: 276479 次
  • 性别: Icon_minigender_1
  • 来自: 武汉
社区版块
存档分类
最新评论

有序的循环链表中插入结点

 
阅读更多

题目

给定一个有序的循环链表,在其中插入一个值,保持该循环链表依然有序。

分析

首先看下循环链表的结构,如下图所示为一个循环链表,其尾结点指向头结点,从而形成一个循环。给定的链表结点可以是链表任意一个结点,这个结点不一定是链表头结点,从而这也增加了该题的难度。

此时若是要在链表中插入4,则插入后的链表如下所示:

可以看到插入4后,链表依然有序。

在解决这个问题前,先来看一个简化的问题,就是在一个有序单链表中插入结点,仍然保证其有序。这个问题的代码相信多数人都很熟悉,一般都是分两种情况考虑:

1)如果原来链表为空或者插入的结点值最小,则直接插入该结点并设置为头结点。

2)如果原来链表非空,则找到第一个大于该结点值的结点,并插入到该结点的前面。如果插入的结点值最大,则插入在尾部。

代码如下:

//链表结点定义
struct node {
  int data;
  struct node *next;
};
typedef struct node Node;

void sortedInsert3(struct node** headRef, struct node* nd)
{
 if (*headRef==NULL || (*headRef)->data>=nd->data) { //情况1
 nd->next = *headRef;
 *headRef = nd;
 } else {  //情况2
 struct node* current = *headRef;
 while (current->next != NULL && current->next->data < nd->data)
 current = current->next;
 nd->next = current->next;
 current->next = nd;
 }
}

当然也可以把情况1和情况2放到一起考虑,代码会更简洁,如下所示:

void sortedInsert2(struct node** headRef, struct node* nd)
{
    struct node** current = headRef;
    while ( (*current)!=NULL && ((*current)->data<nd->data) ) {
        current = &((*current)->next);
    }
    nd->next = *current;
    *current = nd;
}
上面代码很简洁,注意它是怎么处理特殊情况的。

1)当链表为空或者插入的结点值最小时,则直接跳出循环,设置nd->next=NULL, *headRef=nd.

2)其他情况,则current为待插入结点的位置,直接将其插入即可。包括插入到尾部或者任意常规的位置。


解决方案

解决了一个轻量级的问题之后再来看原题,该题目与上面不同的地方在于它是一个循环链表,那么情况会有所不同,设待插入的结点值为x,则至少需要考虑下面三种情况

1.prev->val ≤ x ≤ current->val:

插入到prev和current之间。

2. x是链表中最小或者最大的值:

插入x到链表头部的前面。

3.回到起始点:
插入到起始点前面。

第1和2种情况还比较容易考虑到,但是第3种情况往往会被忽略,先给出代码,再根据代码来分析这些情况为什么都需要考虑到。

void insert(Node *& aNode, int x) {
  //链表为空,创建节点返回
  if (!aNode) {
    aNode = new Node(x);
    aNode->next = aNode;
    return;
  }
 
  Node *p = aNode;
  Node *prev = NULL;
  do {
    prev = p;
    p = p->next;
    if (x <= p->data && x >= prev->data) break;   // 情况1,找到正常位置返回,如例子中插入4到链表中
    if ((prev->data > p->data) && (x < p->data || x > prev->data)) break; // 情况2,x最小或者最大,插入到链表最前面
  } while (p != aNode);   // 情况3,回到起始结点,停止. 
 
  Node *newNode = newNode(x);
  newNode->next = p;
  prev->next = newNode;
}
1)链表只有一个结点

如果x等于该结点值,则直接在情况1处理。否则情况3处理。

2)链表包含重复值

如果链表为1-*1-1,起始结点为第二个1,则在其中插入2时,由情况3处理,即最终插入到初始结点前面。会变成1-2-1-1.循环链表从第二个1开始,照样是有序的。

分享到:
评论

相关推荐

    单循环链表(带头结点和不带头结点)

    单循环链表是一种常见的数据结构,它在计算机科学中被广泛用于存储和处理有序或无序的数据序列。链表与数组不同,不依赖于物理位置的连续性,而是通过节点间的引用连接彼此。本篇文章将深入探讨单循环链表的概念、...

    Java有序非循环双向链表算法实例

    非循环链表的尾部没有链接回头部,因此遍历链表时,当到达尾部的后继为空时,即可停止,避免了无限循环的风险。这对于编写遍历或搜索算法来说,简化了逻辑处理。 四、Java实现 在Java中,双向链表可以使用内置的`...

    航班订票系统(单向,双向循环链表)

    与单向链表不同,双向循环链表的每个节点不仅有指向前一个节点的指针,还有指向下个节点的指针,而且链表的末尾会链接回链表的头部,形成一个循环。这样的设计使得在链表中进行前后移动变得更为高效,比如在乘客列表...

    循环链表和双向链表

    循环链表是一种特殊的链表结构,其特点在于链表的最后一个节点的指针域不再指向空,而是指向前一个节点,这样整个链表形成一个闭合的环形结构。在循环链表中,由于没有明显的尾端,因此在进行算法操作时需要特别注意...

    单向链表输入 遍历 及插入元素建立有序表

    根据给定的信息,本文将详细解释以下几个核心知识点:创建单向链表、遍历单向链表、在非递减有序链表中插入元素、逆置链表中的元素、合并两个非递减有序链表使其成为非递增有序链表以及如何将一个链表分解成两个链表...

    双向循环链表

    2. 插入节点:在双向循环链表中插入节点需要更新前后两个节点的指针。 ```cpp void insert(int value) { Node* newNode = new Node(); newNode-&gt;data = value; newNode-&gt;next = head-&gt;next; newNode-&gt;prev = ...

    数据结构C++版的双循环链表

    5. **其他操作**:如查找特定元素、反转链表、合并两个有序链表等,都是双循环链表常见的操作。 在使用Visual Studio 2013及以上版本打开源代码时,注意确保编译器设置正确,特别是对于C++11或更高版本的语言标准的...

    PTA 两个有序链表序列的合并

    相比于数组,链表的主要优点在于插入和删除操作通常更高效,因为它只需要改变相邻节点的指针即可,而不需要移动元素。 在这个问题中,我们有两个已排序的链表,我们需要将它们合并成一个新的已排序链表。由于链表是...

    图+查找+排序+循环链表+循环链表+数组+广义表+二叉树与树的转换+哈夫曼树.pptx

    2. **循环链表**:链表是由节点构成的数据结构,每个节点包含数据和指向下一个节点的指针。循环链表的特点在于最后一个节点指回了第一个节点,形成一个闭合的环,便于遍历。插入和删除操作比数组更灵活,但访问速度...

    单链表(非循环链表)

    非循环链表,顾名思义,是指链表的最后一个节点没有指向第一个节点的指针,形成了一个开放的序列。这种链表结构使得插入和删除操作相对数组来说更为灵活,但随机访问则不如数组方便。 链表由一系列节点组成,每个...

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

    在本例中,我们使用了insert函数来插入结点。insert函数中,我们使用while循环来找到合适的插入位置,并将新的结点插入链表中。 四、链表的删除 链表的删除是指从链表中删除一个结点。在本例中,我们使用了del函数...

    单向循环链表实现约瑟夫环.zip

    在提供的"单向循环链表实现约瑟夫环.txt"文件中,可能包含了具体的代码实现或者详细解释,包括节点定义、链表操作(如插入、删除)以及约瑟夫环算法的完整流程。通过阅读和理解这个文件,你可以深入学习如何将理论...

    如何将两个有序链表并为一个有序链表

    在数据结构的学习中,链表是一种重要的线性结构之一,它由一系列节点组成,每个节点包含数据域和指向下一个节点的指针。有序链表是指链表中的元素按照特定顺序(如升序或降序)排列。本篇文章旨在介绍如何将两个已经...

    有序的单链表中插入和删除

    此函数首先从头节点开始寻找合适的插入位置,然后创建新节点并将其插入到链表中。 #### 五、从有序单链表中删除节点 删除有序单链表中的节点时,需要先定位到要删除的节点及其前驱节点,然后修改前驱节点的指针...

    05-链表的插入(PPT).pptx

    在有序链表中,通常我们比较新节点的数据(在这个例子中是学生学号)与当前节点的数据,如果新节点的学号小于等于当前节点的学号,则新节点应插入到当前节点之前。 2. **调整指针**:找到插入点后,我们需要更新...

    C语言实现单向链表的创建、插入,删除节点,和2个链表合并

    本文将详细讲解如何使用C语言在Microsoft Visual C++ 6.0环境下实现单向链表的创建、插入、删除节点以及两个链表的合并。 一、单向链表的基本概念 单向链表是一种线性数据结构,每个元素(称为节点)包含两部分:...

    算法__链表的操作

    3. **比较并插入**:循环比较 `p1` 和 `p2` 所指节点的值,将较小者插入到结果链表中,然后移动对应的指针。 4. **处理剩余节点**:循环结束后,将未遍历完的链表的剩余部分添加到结果链表末尾。 #### 递归方法 ...

    将两个递增的链表合并为一个非递减的链表

    - 如果 `p` 的数据大于 `q` 的数据,则将 `q` 所指节点插入到结果链表中,并移动 `q`。 - 否则,将 `p` 所指节点插入到结果链表中,并移动 `p`。 4. 当其中一个链表遍历完后,将另一个链表的剩余部分直接连接到...

    两个有序链表的合并代码

    相比于数组,链表的优点在于插入和删除操作更加高效,因为只需要改变相邻节点间的指针即可,而无需移动大量数据。 **有序链表**是指链表中的元素按照一定的顺序(例如递增或递减)排列。本例中的有序链表是按数值...

Global site tag (gtag.js) - Google Analytics