交换单链表中的节点

2024-05-12

我正在尝试交换两个节点。例如,如果节点是a and b我正在传递指针
(a-1)->next and (b-1)->next这基本上是节点a and b.

void swap(struct stack **a,struct stack **b)
{
    struct stack *temp1 = *a, *temp2 = *b, *temp3 = *b;      
    *a = *b; 
    (*b)->next = (temp1)->next;
    temp2 = temp1;
    (temp2)->next = temp3->next;
}

我究竟做错了什么?当我在调用函数后尝试打印节点时,这是一个无限循环。请帮忙。


为什么是无限循环?

无限循环是因为列表中的自循环after呼叫swap()功能。在swap()语句后面的代码有错误。

(*b)->next = (temp1)->next; 

Why?:因为在赋值语句之后swap()功能temp1的下一个开始指向b节点。和node[b]循环中的下一个指向自身。还有自循环是因为无限循环,在代码中遍历链表的某个位置。

下面我画了图来展示如何swap()逐步进行。也许这可以帮助您了解您的error:

你没有提到,但我假设链表之间有以下关系a and b: (阅读红色评论)

(步骤1):

+----+----+----+      +---+----+----+
|      one     |----->|    two      |
+----+----+----+      +---+---+-----+
  ^     ^              ^    ^
  |     |              |    |
  |    *a              |   *b
  |                    | 
 temp1                temp2, temp3     "after assignment to temp variables"

(step-2):                   ^
                            | 
*a = *b                     | *a       "<--- next step"

(步骤 3):有缺陷的声明

(*b)->next = (temp1)->next;          "Change link: (temp1)->next; is `two` node"
                                     " *b is `two`,   So Self loop" 


+----+----+----+      +---+----+----+ <---|  
|      one     |      |    two      |-----|
+----+----+----+      +---+---+-----+
  ^                    ^    ^    ^
  |                    |    |    |
  |                    |   *b    *a
  |                    | 
 temp1                temp2, temp3    "  after assignment to temp"

See (temp1)->next;实际上是b你正在分配(*b)->next = (*b)通过做(*b)->next = (temp1)->next;因此添加一个自循环。

(步骤4):
我认为通过图表您可以轻松理解最后两行swap()代码正在做:

temp2 = temp1;
(temp2)->next = temp3->next;

以下是我对这两行的图表:

temp2 = temp1;         
+----+----+----+      +---+----+----+ <---|
|      one     |      |    two      |-----|  "<--- Self loop"
+----+----+----+      +---+---+-----+
  ^                    ^    ^    ^
  |                    |    |    |
  |                    |   *b    *a
  |                    | 
  temp2 = temp1;      temp3  

(步骤 5):即使是函数的最后一行swap()左循环如下:

 (temp2)->next = temp3->next;  " last line of your code"

+----+----+----+      +---+----+----+ <---|
|      one     |----->|    two      |-----|  "<-- Self loop"
+----+----+----+      +---+---+-----+
  ^                    ^    ^    ^
  |                    |    |    |
  |                    |   *b    *a
  |                    | 
temp2 = temp1;          temp3  

所以循环仍然存在于two节点如此无限循环。

如何交换单链表中的两个节点?

一种方法是交换节点的数据,而不是交换节点在链表中的位置(正如我对你的问题的评论). But 你想交换节点的在列表中的位置。
嗯,这很好!如果节点数据量较大,此时最好交换节点的位置而不是交换节点的数据(交换数据将是糟糕的选择)

因为你有单链表,交换列表中的任意两个节点need there 前一个节点地址 too. (这是你在交换逻辑中没有考虑的一点)

为什么需要先前的指针?:
假设在一些成功的插入(推送)操作之后,您的列表变为如下:

 0  <--------TOP - "head"
 9  <--p  
 2    
 6  <--q           
 5  

水平图 - 假设你想交换说两个节点(q) and (p):

+---+    +---+    +---+    +---+    +---+                               
| 0 |--->| 9 |--->| 2 |--->| 6 |--->| 5 |---
+---+    +---+    +---+    +---+    +---+  |                                
 ^        ^                  ^            null  
 |        |                  | 
 |       (q)                (p)   
 (head)  

正如我所说,要交换我们需要先前的指针。你需要考虑以下
(理论上,我正在为特定节点编写(p) and (q)只是为了让解释简单。但我的实现很一般):

在列表先前的指针中:

node[0] points to node[9] that is (q), and 
node[2] points to node[6] that is (p)

node[9] points to node[2]
node[6] points to node[5]     

NOTICE:如果你想交换两个节点说node[ 9 ] and node[ 6 ]那么你应该使用这两个节点之前的节点的指针。
例如:两次交换node[ 9 ] and [ 6 ],您还需要更改下一个指针node[ 0 ]和下一个指针node[ 2 ]在上图中。

交换这两个节点后列表会怎样?

+---+    +---+    +---+    +---+    +---+                               
| 0 |--->| 6 |--->| 2 |--->| 9 |--->| 5 |---
+---+    +---+    +---+    +---+    +---+  |                                
 ^        ^                  ^            null  
 |        |                  | 
 |       (p)                (q)   
 (head) 

之前的节点现在是什么[o] and [2]?
交换后,列出先前的指针

node[0] points to node[6] that is (q), and 
node[2] points to node[9] that is (p)      

And

node[9] points to node[5]
node[6] points to node[2]

所以如果你想交换两个节点;紧邻的前一个节点也会起作用,并且因为列表是单链接列表,所以您也需要前一个指针。

如何找到之前的节点指针?

假设你想交换任意两个节点node[p] and node[q]那么你可以使用head pointer找到前一个节点。

所以交换功能syntax (在我的实现中) 就好像:

void swap(struct stack **head, // head node 
          struct stack **a,    // first candidate node to swap
          struct stack **b);   // first candidate node to swap

你将调用如下函数:

swap(&head, &p, &q);

定义: (要理解代码,请阅读我在几乎每一行添加的注释)

void swap(struct stack **head, 
          struct stack **a, 
          struct stack **b){
  // first check if a agrgument is null                 
  if( (*head) == NULL ||               // Empty list         
        (*a) == NULL || (*b) == NULL){     // one node is null  
       // Nothing to swap, just return 
        printf("\n Nothing to swap, just return \n");
        return;
  }     

  // find previos nodes
  struct stack* pre_a = get_prevnd(*head, *a);
  struct stack* pre_b = get_prevnd(*head, *b);

  //Now swap previous node's next
  if(pre_a) pre_a->next = (*b); // a's previous become b's previous, and 
  if(pre_b) pre_b->next = (*a); // b's previous become a's previous

  //Now swap next fiels of candidate nodes  
  struct stack* temp = NULL;  
    temp = (*a)->next;
  (*a)->next = (*b)->next;
  (*b)->next = temp;

  //change head: if any node was a head 
  if((*head)==(*a)) 
     *head = *b;
  else 
     if((*head)==(*b))  
        *head = *a;
}

In swap()你可以注意到我调用了一个辅助函数get_prevnd(, );。该函数返回列表中前一个节点的地址。在函数中get_prevnd(, );,第一个参数是列表头,第二个参数是您要查找的节点。

// find previous node function()
struct stack* get_prevnd(
                 struct stack* head, 
                 struct stack* a
                ){
    if(head == a){
        // node[a] is first node 
        return NULL;
    }
    struct stack* temp = head; // temp is current node
    struct stack* pre_a = NULL; 

    while(temp && temp!=a){ //search while not reach to end or the node
        pre_a = temp;          // find previous node   
        temp = temp->next;
    }
    if(temp!=a){// node[a] not present in list
        fprintf(stderr, "\n error: node not found!\n");
        exit(EXIT_FAILURE); // bad technique to exit()
    }
    return pre_a;   
}

幸运的是,代码可以工作:)。以下是此代码的在线测试链接。我已经测试了各种输入。

键盘:交换单链表中的节点。 http://codepad.org/3YaGfYxm请检查输出。

And sorry for bad English

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

交换单链表中的节点 的相关文章

随机推荐

  • Laravel:运行队列:在 Windows Azure Web App 上连续监听

    我觉得问这个问题有点傻 但我似乎无法在互联网上找到这个问题的答案 经过几个小时的搜索后 我发现在 Linux 服务器上 您使用 Supervisor 在您的网站上连续运行 php artisanqueue listen 无论有或没有守护进程
  • 如何最好地将 Facebook 评论从 http 移至 https

    我们正在将 Ruby On Rails 网站从 HTTP 迁移到 HTTPS 我们的网站使用fb comments用于捕获各个页面上的用户评论的插件 在我们的测试过程中 我们发现当我们将页面从 HTTP 切换到 HTTPS 时 Facebo
  • Jenkins 管道中的动态变量与 Groovy 方法变量

    我在 Groovy 中有一个用于声明性管道的 Jenkinsfile 以及两个创建的 Jenkins 变量 其名称为 OCP TOKEN VALUE ONE 和 OCP TOKEN VALUE TWO 以及相应的值 当我尝试传递方法变量并在
  • CMake - 作为构建过程的一部分运行测试并将标准输出捕获到文件

    我们有几个单元测试 我们希望将其作为构建过程的一部分运行 为了实现这一目标 我有一个帮助程序脚本 它创建一个运行测试的自定义命令 如果成功 则创建一个文件 test name passed 然后我添加一个自定义目标 test name ru
  • Typescript - 联合类型

    我创建了以下界面 export interface Message date Timestamp Date interface Timestamp seconds number nanoseconds number 不知道为什么 我收到以下
  • ManyToOne 关系上的 Hibernate @Where 注释

    我最近开始重构我的项目 因为我必须在一些表中添加额外的列 额外的列是一个枚举 待定或活动 由于这一更改 我现在需要重构所有查询 以便仅在状态为 活动 时检索行 经过一些研究 我发现我们可以使用 Where 注释来注释实体 当我在简单的列上使
  • 为什么 mex 文件中的 OpenMP 仅产生 1 个线程?

    我是 OpenMP 新手 我有以下代码 使用配置了 MSVS2010 的 Matlab mex 可以正常编译 计算机有 8 个可用处理器 我也使用 matlabpool 检查过 include mex h include
  • Webix 树节点的 Font Awesome 图标

    Webix 与 Font Awesome 集成 http docs webix com desktop icon types html 但是如何使用 Font Awesome 图标代替树中的默认文件夹 文件图标来设置各个节点的样式呢 这是我
  • javax.faces.context.FacesContext.isReleased(FacesContext.java:609) 处的 java.lang.UnsupportedOperationException

    我正在集成 SWF 2 2 1 Primefaces 2 2 1 JSF 2 Spring Security 3 Spring 3 1 0M1 我能够访问 Spring web flow xml 中提到的第一页 但出现以下错误 com su
  • 类型错误:“NodeView”对象不支持项目分配 - NetworkX

    我正在完成本教程 https www datacamp com community tutorials networkx python graph tutorial https www datacamp com community tuto
  • python 中的按钮数组

    我想创建一个按钮网格 单击它们时将切换颜色 目前 每个按钮都会触发右下角的按钮 下面是代码 有两个问题 为什么会这样做以及如何纠正 def main self root Tk frame Frame root frame grid row
  • 如何在水晶报表的页眉中添加图表

    我尝试在水晶报表的页眉中添加图表 但它仅在报表页眉和报表页脚中添加 如何在页眉中添加图表 页眉或详细信息部分中不能有图表 图表仅在报告页眉或页脚中起作用 如果页眉中需要图表 请在页眉中创建子报表 并将图表放置在子报表中
  • maven-jar-plugin 不包含 .gitignore 文件

    我尝试使用maven将应用程序打包成jar文件 不知怎的 除了 gitignore文件被添加到 jar 中 为什么会跳过此文件以及如何禁用此文件 即使我尝试像下面这样包含它 包含也会被忽略 并且 jar 文件仍然为空
  • 如何在iOS社交框架中使用SLRequest获取facebook的电子邮件参数

    我尝试使用以下代码来获取登录 iOS 设置 Facebook 的人的电子邮件 请帮助我如何从 SLRequest 获取电子邮件 void getMyDetails if accountStore accountStore ACAccount
  • 如果我用opengl绘图的话SDL Renderer就没用了吗?

    我正在学习 SDL2 但我也在使用使用 OpenGL 调用的 imgui 库 从我在网上各种博客上读到的内容来看 我无法轻松混合 SDL2 渲染器和 opengl 调用 我要么使用其中之一 要么使用另一个 我读过的大多数教程都使用渲染器 所
  • 如何允许点击穿过 div 但仍然对悬停做出反应?

    说我有divA部分重叠的divB 我怎样才能允许点击divA穿过去divB但仍然有hover悬停时触发divA 我知道pointer events none 这使得点击通过 但也阻止了悬停 我也尝试过以下方法 但它不允许点击失败 docum
  • 如何中止 MongoDB shell 中正在运行的查询?

    我不敢相信我必须问这个问题 但是如何停止我刚刚运行的查询 该查询现在正在运行 并且显然需要很长时间才能在 Mongo shell 中完成 Control C似乎会使外壳崩溃 并吐出大量错误 中建议的愚蠢解决方案这个帖子 https stac
  • 在 VS 包项目中获取 dte2 或 TeamFoundationServerExt 对象?

    我正在开发一个 Visual Studio Package 项目 该项目需要连接到我们的 TFS 要读取当前连接 我需要 TeamFoundationServerExt 对象 我应该能够从 dte2 对象中获取该对象 现在我找到了数百个示例
  • swift 中带有字符的单引号

    我已经完成了 C C Java 这些语言告诉我字符用单引号括起来 主要是在遵守正确的语法时 但字符串是双引号的 Swift 的语法是否只允许字符位于单引号内 或者提供这种语法背后有一些有效的原因 逻辑 let char1 Character
  • 交换单链表中的节点

    我正在尝试交换两个节点 例如 如果节点是a and b我正在传递指针 a 1 gt next and b 1 gt next这基本上是节点a and b void swap struct stack a struct stack b str