a905448839 发表于 2023-6-18 18:13:56

(悬赏贴)求个大佬求助,帮我解答一下本题

本题要求实现一个函数,将两个链表表示的递增整数序列合并为一个非递减的整数序列。

函数接口定义:

List Merge( List L1, List L2 );

其中List结构定义如下:

typedef struct Node *PtrToNode;
struct Node {
    ElementType Data; /* 存储结点数据 */
    PtrToNode   Next; /* 指向下一个结点的指针 */
};
typedef PtrToNode List; /* 定义单链表类型 */

L1和L2是给定的带头结点的单链表,其结点存储的数据是递增有序的;函数Merge要将L1和L2合并为一个非递减的整数序列。应直接使用原序列中的结点,返回归并后的带头结点的链表头指针。

裁判测试程序样例:

#include <stdio.h>
#include <stdlib.h>

typedef int ElementType;
typedef struct Node *PtrToNode;
struct Node {
    ElementType Data;
    PtrToNode   Next;
};
typedef PtrToNode List;

List Read(); /* 细节在此不表 */
void Print( List L ); /* 细节在此不表;空链表将输出NULL */

List Merge( List L1, List L2 );

int main()
{
    List L1, L2, L;
    L1 = Read();
    L2 = Read();
    L = Merge(L1, L2);
    Print(L);
    Print(L1);
    Print(L2);
    return 0;
}

/* 你的代码将被嵌在这里 */



我的代码:
List Merge( List L1, List L2 )
{
    List head,temp;
    head = temp = (List)malloc(sizeof(struct Node));
   
      L1 = L1->Next;
      L2 = L2->Next;


      while(L1 && L2)
   {
      if(L1->Data <= L2->Data)
      {
                temp->Next = L1;
                L1 = L1->Next;
      }
      else
      {
                temp->Next = L2;
                L2 = L2->Next;
      }
      temp = temp->Next;
    }
   
    if(L1)
    {
      while(L1)
      {
            temp->Next = L1;
            L1 = L1->Next;
            temp = temp->Next;
      }
      temp->Next = NULL;
    }
   
    else if(L2)
    {
         while(L2)
      {
            temp->Next = L2;
            L2 = L2->Next;
            temp = temp->Next;
      }
      temp->Next = NULL;
    }
    else
      temp->Next = NULL;

    //到这里L1 L2为NULL 运行到后面在main函数里打印出L1 L2为原始头节点。。


    return head;
}


实例测试:

结果图片:



我在函数里通过传进去结构体指针L1 L2修改L1 L2的节点位置 最后返回head最后在main函数里打印出来的链表却是原始节点 按照正常情况下在Merge函数里 L1 L2都为NULL。

函数是传值操作,但是传入的L1 L2是结构体指针所以传入的L1 L2应该是地址吧?那为什么在Merge函数里做的修改都没有用那如果需要修改 要怎样才行呢?

比如在main函数里 a = 4;int *p = a;我把p传进一个函数里做修改,最后回到main函数里打印a的值 能够做修改这里传递指针p和结构体指针有什么区别呢? 为什么结构体指针传进去不能做修改呢? 求解答 十分感谢!

人造人 发表于 2023-6-18 18:13:57

我确实没认真看题,^_^
我是先直接看的代码

#include <stdio.h>
#include <stdlib.h>

typedef int ElementType;
typedef struct Node *PtrToNode;

struct Node {
    ElementType Data;
    PtrToNode Next;
};

typedef PtrToNode List;

List Read(); /* 细节在此不表 (也就是说提交的时候可以不考虑,不过还是要写的!) */
void Print(List L); /* 细节在此不表;空链表将输出NULL   (同上)*/
List Merge(List L1, List L2);


// 你是不是忘了写这个函数了?
void list_free(List L) {
    if(L) list_free(L->Next);
    free(L);
}

int main(void) {
    List L1, L2, L;
    L1 = Read();
    L2 = Read();
    L = Merge(L1, L2);
    Print(L);
    Print(L1);
    Print(L2);
    list_free(L);

    // 现在就可以free了
    list_free(L1);
    list_free(L2);
    // 要共用节点的话,这两个就只能单独释放了
    //free(L1);
    //free(L2);
    return 0;
}

/* 你的代码将被嵌在这里 */
List Read() {
    int n, i;
    scanf("%d", &n);
    //List L = (List)malloc(sizeof(PtrToNode)); /// 申请一个头结点
    //List L = malloc(sizeof(PtrToNode));       // 这是C语言,没必要强制转换
    //List L = malloc(sizeof(struct Node));   // 是PtrToNode还是struct Node?
    List L = malloc(sizeof(*L));                // 对吧?管他什么类型了
    L->Next = NULL;                           // 头指针为空
    if(n)                                     // 当n不是0时
    {
      List r = L; /// r是一个中间变量的节点
      for(i = 0; i < n; i++) {
            //List p = (List)malloc(sizeof(struct Node));
            List p = malloc(sizeof(*p));
            //scanf("%d", &(p->Data)); // 尾插法
            scanf("%d", &p->Data);// 尾插法
            r->Next = p;
            r = p;
      }
      r->Next = NULL;
    }
    return L;
}

void Print(List L) {
    List p = L->Next;
    if(p) {
      List r;
      r = L;
      while(r->Next) {
            r = r->Next;
            printf("%d ", r->Data);
      }
    } else {
      printf("NULL");
    }
    printf("\n");
}

#if 0
// 好了,知道定义了
List Merge(List L1, List L2) {
    List L = malloc(sizeof(*L));
    L->Next = NULL;
    List *px = &L->Next;
    List p1 = L1->Next;
    List p2 = L2->Next;
    while(p1 && p2) {
      ElementType v;
      ElementType a = p1->Data;
      ElementType b = p2->Data;
      if(a < b) {
            v = a; p1 = p1->Next;
      } else {
            v = b; p2 = p2->Next;
      }
      *px = malloc(sizeof(**px));
      (*px)->Data = v;
      (*px)->Next = NULL;
      px = &(*px)->Next;
    }
    while(p1) {
      *px = malloc(sizeof(**px));
      (*px)->Data = p1->Data;
      (*px)->Next = NULL;
      p1 = p1->Next;
      px = &(*px)->Next;
    }
    while(p2) {
      *px = malloc(sizeof(**px));
      (*px)->Data = p2->Data;
      (*px)->Next = NULL;
      p2 = p2->Next;
      px = &(*px)->Next;
    }
    return L;
}
#else
List Merge(List L1, List L2) {
    List head, temp;
    //head = temp = (List)malloc(sizeof(struct Node));
    head = temp = malloc(sizeof(*head));

    List L1_bak = L1;
    List L2_bak = L2;

    L1 = L1->Next;
    L2 = L2->Next;

    while(L1 && L2) {
      if(L1->Data <= L2->Data) {
            temp->Next = L1;
            L1 = L1->Next;
      } else {
            temp->Next = L2;
            L2 = L2->Next;
      }
      temp = temp->Next;
    }

    if(L1) {
      while(L1) {
            temp->Next = L1;
            L1 = L1->Next;
            temp = temp->Next;
      }
      temp->Next = NULL;
    }
    else if(L2) {
      while(L2) {
            temp->Next = L2;
            L2 = L2->Next;
            temp = temp->Next;
      }
      temp->Next = NULL;
    } else
      temp->Next = NULL;

    // 到这里L1 L2为NULL 运行到后面在main函数里打印出L1 L2为原始头节点。。
    L1_bak->Next = NULL;
    L2_bak->Next = NULL;

    return head;
}
#endif

歌者文明清理员 发表于 2023-6-18 18:18:44

函数参数传递分为值传递和指针传递。对于基本类型的值传递,传入的是该值的副本,修改该副本不会对原始值造成影响;而对于指针类型的值传递,传入的是指针所指向地址的副本,这个副本指向同一个地址,因此可以通过该指针修改原始值。结构体指针也是指针类型,如果传入 Merge 函数的是 L1 和 L2 的指针,那么在函数内部修改 L1 和 L2 就可以作用到原始链表的头结点上了。可能你的问题出在 L1 和 L2 是值传递而非指针传递,导致在 Merge 函数中做的修改不能反映到 main 函数里。

sfqxx 发表于 2023-6-18 18:21:19

在C语言中,函数参数的传递方式可以是值传递或地址传递。对于基本数据类型(如int、float等),采用值传递的方式,即将变量的值复制给形式参数,在函数内部对形参的修改不会影响到实参的值。而对于指针类型,采用地址传递的方式,即将实参的地址传递给形式参数,函数内部通过操作该地址所指向的内存,可以修改实参所指向的数据。

在你的代码中,`List`类型是指向结构体 `Node` 的指针类型,当你将 `L1` 和 `L2` 作为函数参数进行传递时,实际上是将它们的值(即结构体指针的地址)复制给了函数内部的形参 `L1` 和 `L2`。因此,在函数内部修改 `L1` 和 `L2` 的指向并不会影响原始的链表头节点。

要解决这个问题,可以考虑使用指向指针的指针(双重指针)来实现地址传递,以达到在函数内部修改链表头节点的目的。函数声明和定义需要做以下修改:


List Merge(List* L1, List* L2);

在函数内部,通过对指针的间接引用,修改指针指向的值即可:

List Merge(List* L1, List* L2) {
    List head, temp;
    head = temp = (List)malloc(sizeof(struct Node));

    *L1 = (*L1)->Next;// 修改L1指针指向的值,使其指向下一个节点
    *L2 = (*L2)->Next;// 修改L2指针指向的值,使其指向下一个节点

    // 其他代码不变...

    return head;
}

在函数调用时,传入 `&L1` 和 `&L2`,以传递它们的地址(即指向指针的指针):

L = Merge(&L1, &L2);

这样,在函数内部对 `L1` 和 `L2` 的操作就能够影响到原始的链表头节点了。

求最佳答案{:10_254:}

a905448839 发表于 2023-6-18 18:28:17

sfqxx 发表于 2023-6-18 18:21
在C语言中,函数参数的传递方式可以是值传递或地址传递。对于基本数据类型(如int、float等),采用值传递 ...

我只能在Merge函数里做修改,参数只能是这样List Merge( List L1, List L2 ),我该如何解决呢?

a905448839 发表于 2023-6-18 18:34:17

sfqxx 发表于 2023-6-18 18:21
在C语言中,函数参数的传递方式可以是值传递或地址传递。对于基本数据类型(如int、float等),采用值传递 ...

将 `L1` 和 `L2` 作为函数参数进行传递时,实际上是将它们的值(即结构体指针的地址)复制给了函数内部的形参 `L1` 和 `L2`。 那么传递&L1和&L2 实际上是传递的什么呢?

a905448839 发表于 2023-6-18 20:23:52

有人吗?

a905448839 发表于 2023-6-18 20:30:33

List Merge( List L1, List L2 )
{
    List head,temp,TL1,TL2;
    head = temp = (List)malloc(sizeof(struct Node));
   
   
      TL1 = L1->Next;
      TL2 = L2->Next;


      while(TL1 && TL2)
   {
      if(TL1->Data <= TL2->Data)
      {
                temp->Next = TL1;
                TL1 = TL1->Next;
      }
      else
      {
                temp->Next = TL2;
                TL2 = TL2->Next;
      }
      temp = temp->Next;
    }
   
    if(TL1)
    {
      while(TL1)
      {
            temp->Next = TL1;
            TL1 = TL1->Next;
            temp = temp->Next;
      }
      temp->Next = NULL;
    }
   
    else if(TL2)
    {
         while(TL2)
      {
            temp->Next = TL2;
            TL2 = TL2->Next;
            temp = temp->Next;
      }
      temp->Next = NULL;
    }
    else
      temp->Next = NULL;

    //到这里L1 L2为NULL 运行到后面在main函数里打印出L1 L2为原始头节点。。
L1->Next = NULL;
L2->Next = NULL;

    return head;
}

代码修改一下就可以了 真的希望有大佬出来解释一下

a905448839 发表于 2023-6-18 20:36:59

@isdkz 能帮我看看吗?

陶远航 发表于 2023-6-18 20:42:26

在C语言中,函数参数传递有两种方式:传值和传址。传值是将参数的值拷贝一份传入函数内部,对参数的修改不会影响原始值;而传址是将参数的内存地址传入函数内部,因此对参数的修改会直接反映到原始值上。

对于指针类型的参数,传递时一般是传递指针的值,即指针变量所指向的内存地址。这样做相当于传址,因为函数内部可以通过指针来访问原始值的内存地址,并对其值进行修改。

回到你的问题,你在Merge函数中对L1和L2指针的修改并不能影响main函数中的L1和L2的值,因为你修改的是指针变量本身的值,而非其指向的内存地址的值。要想在Merge函数中修改L1和L2的值,可以使用指向指针的指针或者指针的引用作为函数参数,这样可以实现对指针变量本身的修改,从而使得修改在函数外部可见。

以下是使用指针的指针实现对L1和L2的修改的示例代码:

List Merge( List* pL1, List* pL2 )
{
    List head,temp;
    head = temp = (List)malloc(sizeof(struct Node));
   
    List L1 = (*pL1)->Next;
    List L2 = (*pL2)->Next;

    while(L1 && L2)
    {
      if(L1->Data <= L2->Data)
      {
            temp->Next = L1;
            L1 = L1->Next;
      }
      else
      {
            temp->Next = L2;
            L2 = L2->Next;
      }
      temp = temp->Next;
    }
   
    if(L1)
    {
      while(L1)
      {
            temp->Next = L1;
            L1 = L1->Next;
            temp = temp->Next;
      }
      temp->Next = NULL;
    }
    else if(L2)
    {
      while(L2)
      {
            temp->Next = L2;
            L2 = L2->Next;
            temp = temp->Next;
      }
      temp->Next = NULL;
    }
    else
      temp->Next = NULL;

    *pL1 = head; // 修改 L1 指针的值,使其指向合并后的链表头
    (*pL2)->Next = NULL; // 将 L2 头节点的 Next 指针置为 NULL,防止出现错误

    return head;
}

在main函数中,可以这样调用Merge函数:

L = Merge(&L1, &L2);

注意,由于L1和L2都是带头结点的链表,所以在Merge函数返回之前要将它们的头节点的Next指针置为NULL,以免出现链接关系错乱的情况。

如果只能在Merge函数里做修改,那么最简单的方式是使用一个新的指针变量p指向head,然后在函数中修改p的值即可,这样就不会修改原始的L1和L2指针了。具体实现如下:

List Merge( List L1, List L2 )
{
    List head,temp,p;
    head = temp = (List)malloc(sizeof(struct Node));
    p = head; // 新增一个指针p,指向head
   
    L1 = L1->Next;
    L2 = L2->Next;

    while(L1 && L2)
    {
      if(L1->Data <= L2->Data)
      {
            p->Next = L1; // 使用p指针更新链表
            L1 = L1->Next;
      }
      else
      {
            p->Next = L2; // 使用p指针更新链表
            L2 = L2->Next;
      }
      p = p->Next;
    }
   
    if(L1)
    {
      while(L1)
      {
            p->Next = L1;
            L1 = L1->Next;
            p = p->Next;
      }
      p->Next = NULL;
    }
    else if(L2)
    {
      while(L2)
      {
            p->Next = L2;
            L2 = L2->Next;
            p = p->Next;
      }
      p->Next = NULL;
    }
    else
      p->Next = NULL;

    return head;
}

调用方式与之前相同:

L = Merge(L1, L2);

需要注意的是,在Merge函数中只要涉及到链表的插入、删除、移动等操作,都需要使用p指针来修改链表结构,以免影响原始的L1和L2指针。

a905448839 发表于 2023-6-18 21:03:39

有没有一个不是人工智能回答的呀,有没有真人回答一下

本题我已测试过L1 L2是一个结构体指针 传进Merge函数里做修改 main函数打印也会改变如图:

@小甲鱼 他们的回答都是通过L1 L2在Merge函数修改节点位置在main函数里是无法修改的而在Merge函数里通过L1 L2头节点下一个指NULL时在main函数里打印的NULL 能够被修改

a905448839 发表于 2023-6-18 21:47:51

完整的测试代码
#include <stdio.h>
#include <stdlib.h>

typedef int ElementType;
typedef struct Node *PtrToNode;
struct Node {
    ElementType Data;
    PtrToNode   Next;
};
typedef PtrToNode List;

List Read(); /* 细节在此不表   (也就是说提交的时候可以不考虑,不过还是要写的!)    */
void Print( List L ); /* 细节在此不表;空链表将输出NULL   (同上)*/

List Merge( List L1, List L2 );

int main()
{
    List L1, L2, L;
    L1 = Read();
    L2 = Read();
    L = Merge(L1, L2);
    Print(L);
    Print(L1);
    Print(L2);
    return 0;
}

/* 你的代码将被嵌在这里 */
List Read()
{
    int n,i;
    scanf("%d",&n);
    List L=(List)malloc(sizeof(PtrToNode));   ///申请一个头结点
    L->Next = NULL;      ///头指针为空
    if(n)    ///当n不是0时
    {
      List r=L;   ///r是一个中间变量的节点
      for(i=0;i<n;i++)
      {
            List p=(List)malloc(sizeof(struct Node));
            scanf("%d",&(p->Data));    ///尾插法
            r->Next = p;
            r = p;
      }
      r->Next = NULL;         
    }
    return L;
}

void Print( List L )
{
   List p=L->Next;
   if(p)
   {
       List r;
       r = L;
       while(r->Next)
       {
         r = r->Next;
         printf("%d ",r->Data);
       }
   }
   else
   {
       printf("NULL");
   }
   printf("\n");
}

人造人 发表于 2023-6-18 23:00:00

a905448839 发表于 2023-6-18 21:03
有没有一个不是人工智能回答的呀,有没有真人回答一下

本题我已测试过L1 L2是一个结构体指针 传进Merge ...

那就来个不是ai的回答
#include <stdio.h>
#include <stdlib.h>

typedef int ElementType;
typedef struct Node *PtrToNode;

struct Node {
    ElementType Data;
    PtrToNode Next;
};

typedef PtrToNode List;

List Read(); /* 细节在此不表 (也就是说提交的时候可以不考虑,不过还是要写的!) */
void Print(List L); /* 细节在此不表;空链表将输出NULL   (同上)*/
List Merge(List L1, List L2);


// 你是不是忘了写这个函数了?
void list_free(List L) {
    if(L) list_free(L->Next);
    free(L);
}

int main(void) {
    List L1, L2, L;
    L1 = Read();
    L2 = Read();
    L = Merge(L1, L2);
    Print(L);
    Print(L1);
    Print(L2);
    list_free(L);
    list_free(L1);
    list_free(L2);
    return 0;
}

/* 你的代码将被嵌在这里 */
List Read() {
    int n, i;
    scanf("%d", &n);
    //List L = (List)malloc(sizeof(PtrToNode)); /// 申请一个头结点
    //List L = malloc(sizeof(PtrToNode));       // 这是C语言,没必要强制转换
    //List L = malloc(sizeof(struct Node));   // 是PtrToNode还是struct Node?
    List L = malloc(sizeof(*L));                // 对吧?管他什么类型了
    L->Next = NULL;                           // 头指针为空
    if(n)                                     // 当n不是0时
    {
      List r = L; /// r是一个中间变量的节点
      for(i = 0; i < n; i++) {
            //List p = (List)malloc(sizeof(struct Node));
            List p = malloc(sizeof(*p));
            //scanf("%d", &(p->Data)); // 尾插法
            scanf("%d", &p->Data);// 尾插法
            r->Next = p;
            r = p;
      }
      r->Next = NULL;
    }
    return L;
}

void Print(List L) {
    List p = L->Next;
    if(p) {
      List r;
      r = L;
      while(r->Next) {
            r = r->Next;
            printf("%d ", r->Data);
      }
    } else {
      printf("NULL");
    }
    printf("\n");
}

// 定义是什么?
List Merge(List L1, List L2) {
    List L = malloc(sizeof(*L));
    L->Next = NULL;
    List *px = &L->Next;
    List p1 = L1->Next;
    while(p1) {
      *px = malloc(sizeof(**px));
      (*px)->Data = p1->Data;
      (*px)->Next = NULL;
      p1 = p1->Next;
      px = &(*px)->Next;
    }
    List p2 = L2->Next;
    while(p2) {
      *px = malloc(sizeof(**px));
      (*px)->Data = p2->Data;
      (*px)->Next = NULL;
      p2 = p2->Next;
      px = &(*px)->Next;
    }
    return L;
}

人造人 发表于 2023-6-18 23:08:11

稍微改一改

#include <stdio.h>
#include <stdlib.h>

typedef int ElementType;
typedef struct Node *PtrToNode;

struct Node {
    ElementType Data;
    PtrToNode Next;
};

typedef PtrToNode List;

List Read(); /* 细节在此不表 (也就是说提交的时候可以不考虑,不过还是要写的!) */
void Print(List L); /* 细节在此不表;空链表将输出NULL   (同上)*/
List Merge(List L1, List L2);


// 你是不是忘了写这个函数了?
void list_free(List L) {
    if(L) list_free(L->Next);
    free(L);
}

int main(void) {
    List L1, L2, L;
    L1 = Read();
    L2 = Read();
    L = Merge(L1, L2);
    Print(L);
    Print(L1);
    Print(L2);
    list_free(L);
    list_free(L1);
    list_free(L2);
    return 0;
}

/* 你的代码将被嵌在这里 */
List Read() {
    int n, i;
    scanf("%d", &n);
    //List L = (List)malloc(sizeof(PtrToNode)); /// 申请一个头结点
    //List L = malloc(sizeof(PtrToNode));       // 这是C语言,没必要强制转换
    //List L = malloc(sizeof(struct Node));   // 是PtrToNode还是struct Node?
    List L = malloc(sizeof(*L));                // 对吧?管他什么类型了
    L->Next = NULL;                           // 头指针为空
    if(n)                                     // 当n不是0时
    {
      List r = L; /// r是一个中间变量的节点
      for(i = 0; i < n; i++) {
            //List p = (List)malloc(sizeof(struct Node));
            List p = malloc(sizeof(*p));
            //scanf("%d", &(p->Data)); // 尾插法
            scanf("%d", &p->Data);// 尾插法
            r->Next = p;
            r = p;
      }
      r->Next = NULL;
    }
    return L;
}

void Print(List L) {
    List p = L->Next;
    if(p) {
      List r;
      r = L;
      while(r->Next) {
            r = r->Next;
            printf("%d ", r->Data);
      }
    } else {
      printf("NULL");
    }
    printf("\n");
}

// 好了,知道定义了
List Merge(List L1, List L2) {
    List L = malloc(sizeof(*L));
    L->Next = NULL;
    List *px = &L->Next;
    List p1 = L1->Next;
    List p2 = L2->Next;
    while(p1 && p2) {
      ElementType v;
      ElementType a = p1->Data;
      ElementType b = p2->Data;
      if(a < b) {
            v = a; p1 = p1->Next;
      } else {
            v = b; p2 = p2->Next;
      }
      *px = malloc(sizeof(**px));
      (*px)->Data = v;
      (*px)->Next = NULL;
      px = &(*px)->Next;
    }
    while(p1) {
      *px = malloc(sizeof(**px));
      (*px)->Data = p1->Data;
      (*px)->Next = NULL;
      p1 = p1->Next;
      px = &(*px)->Next;
    }
    while(p2) {
      *px = malloc(sizeof(**px));
      (*px)->Data = p2->Data;
      (*px)->Next = NULL;
      p2 = p2->Next;
      px = &(*px)->Next;
    }
    return L;
}

人造人 发表于 2023-6-18 23:24:19

#include <stdio.h>
#include <stdlib.h>

typedef int ElementType;
typedef struct Node *PtrToNode;

struct Node {
    ElementType Data;
    PtrToNode Next;
};

typedef PtrToNode List;

List Read(); /* 细节在此不表 (也就是说提交的时候可以不考虑,不过还是要写的!) */
void Print(List L); /* 细节在此不表;空链表将输出NULL   (同上)*/
List Merge(List L1, List L2);


// 你是不是忘了写这个函数了?
void list_free(List L) {
    if(L) list_free(L->Next);
    free(L);
}

int main(void) {
    List L1, L2, L;
    L1 = Read();
    L2 = Read();
    L = Merge(L1, L2);
    Print(L);
    Print(L1);
    Print(L2);
    list_free(L);
    //list_free(L1);
    //list_free(L2);
    // 要共用节点的话,这两个就只能单独释放了
    free(L1);
    free(L2);
    return 0;
}

/* 你的代码将被嵌在这里 */
List Read() {
    int n, i;
    scanf("%d", &n);
    //List L = (List)malloc(sizeof(PtrToNode)); /// 申请一个头结点
    //List L = malloc(sizeof(PtrToNode));       // 这是C语言,没必要强制转换
    //List L = malloc(sizeof(struct Node));   // 是PtrToNode还是struct Node?
    List L = malloc(sizeof(*L));                // 对吧?管他什么类型了
    L->Next = NULL;                           // 头指针为空
    if(n)                                     // 当n不是0时
    {
      List r = L; /// r是一个中间变量的节点
      for(i = 0; i < n; i++) {
            //List p = (List)malloc(sizeof(struct Node));
            List p = malloc(sizeof(*p));
            //scanf("%d", &(p->Data)); // 尾插法
            scanf("%d", &p->Data);// 尾插法
            r->Next = p;
            r = p;
      }
      r->Next = NULL;
    }
    return L;
}

void Print(List L) {
    List p = L->Next;
    if(p) {
      List r;
      r = L;
      while(r->Next) {
            r = r->Next;
            printf("%d ", r->Data);
      }
    } else {
      printf("NULL");
    }
    printf("\n");
}

#if 0
// 好了,知道定义了
List Merge(List L1, List L2) {
    List L = malloc(sizeof(*L));
    L->Next = NULL;
    List *px = &L->Next;
    List p1 = L1->Next;
    List p2 = L2->Next;
    while(p1 && p2) {
      ElementType v;
      ElementType a = p1->Data;
      ElementType b = p2->Data;
      if(a < b) {
            v = a; p1 = p1->Next;
      } else {
            v = b; p2 = p2->Next;
      }
      *px = malloc(sizeof(**px));
      (*px)->Data = v;
      (*px)->Next = NULL;
      px = &(*px)->Next;
    }
    while(p1) {
      *px = malloc(sizeof(**px));
      (*px)->Data = p1->Data;
      (*px)->Next = NULL;
      p1 = p1->Next;
      px = &(*px)->Next;
    }
    while(p2) {
      *px = malloc(sizeof(**px));
      (*px)->Data = p2->Data;
      (*px)->Next = NULL;
      p2 = p2->Next;
      px = &(*px)->Next;
    }
    return L;
}
#else
List Merge(List L1, List L2) {
    List head, temp;
    //head = temp = (List)malloc(sizeof(struct Node));
    head = temp = malloc(sizeof(*head));

    L1 = L1->Next;
    L2 = L2->Next;

    while(L1 && L2) {
      if(L1->Data <= L2->Data) {
            temp->Next = L1;
            L1 = L1->Next;
      } else {
            temp->Next = L2;
            L2 = L2->Next;
      }
      temp = temp->Next;
    }

    if(L1) {
      while(L1) {
            temp->Next = L1;
            L1 = L1->Next;
            temp = temp->Next;
      }
      temp->Next = NULL;
    }
    else if(L2) {
      while(L2) {
            temp->Next = L2;
            L2 = L2->Next;
            temp = temp->Next;
      }
      temp->Next = NULL;
    } else
      temp->Next = NULL;

    // 到这里L1 L2为NULL 运行到后面在main函数里打印出L1 L2为原始头节点。。

    return head;
}
#endif

a905448839 发表于 2023-6-18 23:42:43

人造人 发表于 2023-6-18 23:08
稍微改一改

感谢你的回复,真的很牛,不过这二级指针我越看越迷糊,我也free不了内存空间,我只能对Merge函数内容做出修改,参数也不能更改。main函数也不能动。我把你的代码copy过去测试了,我把测试结果发出来。




你的第一次回复 Merge函数代码 测试:
List Merge(List L1, List L2) {
    List L = malloc(sizeof(*L));
    L->Next = NULL;
    List *px = &L->Next;
    List p1 = L1->Next;
    while(p1) {
      *px = malloc(sizeof(**px));
      (*px)->Data = p1->Data;
      (*px)->Next = NULL;
      p1 = p1->Next;
      px = &(*px)->Next;
    }
    List p2 = L2->Next;
    while(p2) {
      *px = malloc(sizeof(**px));
      (*px)->Data = p2->Data;
      (*px)->Next = NULL;
      p2 = p2->Next;
      px = &(*px)->Next;
    }
    return L;
}




你的第二次回复 Merge函数代码 测试:
List Merge(List L1, List L2) {
    List L = malloc(sizeof(*L));
    L->Next = NULL;
    List *px = &L->Next;
    List p1 = L1->Next;
    List p2 = L2->Next;
    while(p1 && p2) {
      ElementType v;
      ElementType a = p1->Data;
      ElementType b = p2->Data;
      if(a < b) {
            v = a; p1 = p1->Next;
      } else {
            v = b; p2 = p2->Next;
      }
      *px = malloc(sizeof(**px));
      (*px)->Data = v;
      (*px)->Next = NULL;
      px = &(*px)->Next;
    }
    while(p1) {
      *px = malloc(sizeof(**px));
      (*px)->Data = p1->Data;
      (*px)->Next = NULL;
      p1 = p1->Next;
      px = &(*px)->Next;
    }
    while(p2) {
      *px = malloc(sizeof(**px));
      (*px)->Data = p2->Data;
      (*px)->Next = NULL;
      p2 = p2->Next;
      px = &(*px)->Next;
    }
    return L;
}



也许大佬你没有仔细看题实现这个题目最后L1 L2指向的下一个节点是NULL由于我的代码是通过传递进去的L1 L2指针来进行改动移动节点 导致回到主函数中去的时候好像没有改动到L1 L2节点位置 还依然是头节点 我看过一些题解是用两个局部变量的指针指向L1 L2 再来做这两个局部变量的指针移动节点 最后把L1 L2指向的下一个节点为NULL 有这样一段代码实现 我不明白的是 为什么用完局部变量的节点之后最后L1->Next = NULL和L2->Next = NULL 是能够影响到外面main函数的L1 L2。而直接对L1 L2修改 直到L1 L2都为NULL时返回到main函数,main函数里的L1 L2依然为最开始头节点。

能够实现的代码 使用两个局部变量来移动节点用temp来指向产生一个新的链表最后让始终是L1 L2头结点下一个指向NULL成功影响外面的main函数里的L1 L2:
List Merge( List L1, List L2 )
{
    List head,temp,TL1,TL2;
    head = temp = (List)malloc(sizeof(struct Node));
   
   
      TL1 = L1->Next;
      TL2 = L2->Next;


      while(TL1 && TL2)
   {
      if(TL1->Data <= TL2->Data)
      {
                temp->Next = TL1;
                TL1 = TL1->Next;
      }
      else
      {
                temp->Next = TL2;
                TL2 = TL2->Next;
      }
      temp = temp->Next;
    }
   
    if(TL1)
    {
      while(TL1)
      {
            temp->Next = TL1;
            TL1 = TL1->Next;
            temp = temp->Next;
      }
      temp->Next = NULL;
    }
   
    else if(TL2)
    {
         while(TL2)
      {
            temp->Next = TL2;
            TL2 = TL2->Next;
            temp = temp->Next;
      }
      temp->Next = NULL;
    }
    else
      temp->Next = NULL;

   
L1->Next = NULL;
L2->Next = NULL;

    return head;
}

不能够实现的代码对传进来L1 L2结构体指针操作能够实现让两个链表合并成一个递增的顺序链表 但是L1 L2在Merge函数结束时为NULL 回到main函数却变成了最开始L1 L2的头指针:
List Merge( List L1, List L2 )
{
    List head,temp;
    head = temp = (List)malloc(sizeof(struct Node));
   
      L1 = L1->Next;
      L2 = L2->Next;


      while(L1 && L2)
   {
      if(L1->Data <= L2->Data)
      {
                temp->Next = L1;
                L1 = L1->Next;
      }
      else
      {
                temp->Next = L2;
                L2 = L2->Next;
      }
      temp = temp->Next;
    }
   
    if(L1)
    {
      while(L1)
      {
            temp->Next = L1;
            L1 = L1->Next;
            temp = temp->Next;
      }
      temp->Next = NULL;
    }
   
    else if(L2)
    {
         while(L2)
      {
            temp->Next = L2;
            L2 = L2->Next;
            temp = temp->Next;
      }
      temp->Next = NULL;
    }
    else
      temp->Next = NULL;

    //到这里L1 L2为NULL 运行到后面在main函数里打印出L1 L2为原始头节点。。


    return head;
}

人造人 发表于 2023-6-19 00:49:54

a905448839 发表于 2023-6-18 23:42
感谢你的回复,真的很牛,不过这二级指针我越看越迷糊,我也free不了内存空间,我只能对Merge函数内容做 ...

这里需要修改的是L->Next

L1 = L1->Next;
L1->Next = NULL;
这个修改的就是 L->Next->Next 了

L1 = L1->Next;
L1->Next = NULL;

L->Next->Next = NULL;

他俩一个意思

人造人 发表于 2023-6-19 00:59:17

#include <stdio.h>
#include <stdlib.h>

typedef int ElementType;
typedef struct Node *PtrToNode;

struct Node {
    ElementType Data;
    PtrToNode Next;
};

typedef PtrToNode List;

void Print(List L); /* 细节在此不表;空链表将输出NULL   (同上)*/


void list_free(List L) {
    if(L) list_free(L->Next);
    free(L);
}

void set_null(List a, List b) {

    a->Next->Next = NULL;

    b = b->Next;
    b->Next = NULL;
}

int main(void) {
    List L1, L2;
    L1 = malloc(sizeof(*L1));
    L1->Next = malloc(sizeof(*L1->Next));
    L1->Next->Data = 123;
    L2 = malloc(sizeof(*L2));
    L2->Next = malloc(sizeof(*L2->Next));
    L2->Next->Data = 456;
    set_null(L1, L2);
    Print(L1);
    Print(L2);
    list_free(L1);
    list_free(L2);
    return 0;
}

void Print(List L) {
    List p = L->Next;
    if(p) {
      List r;
      r = L;
      while(r->Next) {
            r = r->Next;
            printf("%d ", r->Data);
      }
    } else {
      printf("NULL");
    }
    printf("\n");
}

a905448839 发表于 2023-6-19 10:12:20

人造人 发表于 2023-6-18 18:13
我确实没认真看题,^_^
我是先直接看的代码

感谢你的回答 两种方式我都看了! 最后还有一个小问题 在第二个Merge函数里最后L1_bak->Next = NULL;
    L2_bak->Next = NULL; 这里的L1_bak和L2_bak原本是L1 L2头结点位置这里指向NULL 让main函数L1 L2的下一节点指向NULL了 的的确确影响到了 但是如果在Merge函数里移动L1 L2节点 或者移动L1_bak L2_bak节点 最后在移动的中途节点 或者在最后节点再把下一个节点指向NULL 就不会导致main函数里的L1 L2节点下一个指向为NULL 是原始的情况 是否在Merge函数里移动这些节点 不会导致main函数里的L1 L2节点位置改变 但是如果在Merge函数里直接做指向节点修改 不移动节点就会影响到main函数里的L1 L2指向吗?

人造人 发表于 2023-6-19 10:13:59

a905448839 发表于 2023-6-19 10:12
感谢你的回答 两种方式我都看了! 最后还有一个小问题 在第二个Merge函数里最后L1_bak->Next = NULL;
   ...

没看懂,用代码说明你的问题吧
页: [1] 2
查看完整版本: (悬赏贴)求个大佬求助,帮我解答一下本题