02-线性结构1 两个有序链表序列的合并 (15 分)

                        02-线性结构1 两个有序链表序列的合并 (15分)

#此题属于入门1题目

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

##Combine Link Listed

  • 考察点

    • same 输入输出的例子
    • 两个完全一样的链表
    • 两个空链表
    • L2完全贴在L1后面
    • L1完全贴在L2后面

    让我们来翻译以上考擦点
    1.例子中的输出和输入==比较节点的大小 小的先放入链表L
    2. 两个从排序和大小完全相同的链表
    3. 两个空链表 除了拥有头结点
    4. L2链表任意节点都大于L1任意节点
    5. L1链表任意节点大于L2任意节点

    接下来我们逐步解决每一个问题

    结构体数据

typedef int ElementType;
typedef struct Node *PtrToNode; //struct Node 
struct Node {
    ElementType Data;
    PtrToNode   Next;
};
typedef PtrToNode List;
List L; //这个就是返回的链表
p1 = L1->Next; //跳过头结点达到首元结点
p2 = L2->Next; // 同上
p3 = L;  //p3 是链表L的指针 此时p3位于头结点
List tail //这个指针表示Node->Next
//再例子中 L1 L2存在大小差异 所以问题的核心是 L1和L2 在L的大小差异
if(p1&&p2){  //解决问题3  两个空链表
for(;p1&&p2){
    if(p1->Data < p2->Data){
        tail = p1->Next; //把p1后一个节点存下来
        p1->Next = NULL  //断开原来节点的练习
        p3->Next = p1; //链接链表L 成为L的一个节点
        p3=p3->Next; //指向链表L的指针前进
        p1 = tail;  //p1指针前进
    }else if(p1->Data > p2->Data){
       tail = p2->Next; //把p2后一个节点存下来
        p2->Next = NULL  //断开原来节点的练习
        p3->Next = p2; //链接链表L 成为L的一个节点
        p3=p3->Next; //指向链表L的指针前进
        p2 = tail;  //p2指针前进
    }else{
           tail = p1->Next; //tail记载当前节点的下一个
           p1->Next = NULL; //断开当前节点与后面的练习
           p3->Next = p1;   //链表L的指针指向p1 完成链接
           p3 = p3->Next;  //L的指针完成前进 
           p1 = tail;      //p1又指回链表L1
           tail = p2->Next;  //同上 
            p2->Next = NULL;
            p3->Next = p2;
            p3 = p3->Next;
             p2 = tail;
             }
} if(p1)
  {
    for(;p1;){
        if(p3->Data <= p1->Data &&p3->Next==NULL){
        tail = p1->Next;
        p3->Next = p1;
        p3 = p3->Next;
        p3->Next = NULL;
        p1 = tail;
        }else {
            printf("Fair");
        }
    }
  }
   if(p2){
      for(;p2;){
     if(p3->Data <= p2->Data&&p3->Next==NULL){
         tail = p2->Next; //记住L2节点的下一个,节点要被移到L上
         p3->Next = p2;
         p3 = p3->Next; //P3指针前进移动至末尾 
         p3->Next = NULL; //将节点与原来链表L2的联系断开
         p2 = tail; //将p2指针移动回原来节点的下一个
     }else {
         printf("Fair!");
     }
      }
  }

p1 = L1; //指向头结点
p2 = L2; //指向头结点
p1->Next = NULL;  //断开
p2->Next = NULL;
}
此时if -else if()这一段代码块 思路是通过两个长短不同的链表进行合并 比较
总会留下一个L1或者L2的剩余链表 还有一个空链表 以及链表L
我们来判断 剩余的是L1还是L2 再然后用剩余的链表来跟链表L比较 
接下来可以解决第二个问题 也就是 else()
也就是两个完全一样的链表
当节点既不是大于也不是小于
就可以分到等于
做法是 一次if完成两个节点的移动与前进 
解决问题三 两个空链表 都是带头节点的空链表只要做判断 判断L1L2是不是空 如果为空就跳过if语句
问题4/5 问题所在可以用if语句来判断 最后最容易被忽视的一点
L1和L2的顺序为上的第一个节点 也就是头结点  头结点此时还是指向原来的首元结点 我们并未对头结点进行断开
所以还要在节点断开 使链表成为空链表 

上面都是解决问题的各小段
下面我出示完整代码


List Merge( List L1,List L2) /*合并两个有序链表成一个递增的有序列表*/
{
    List L = (List)malloc(sizeof(struct Node));
    L->Next = NULL;
    List head = L;
    List p3 = head; //指向头结点 用来遍历链表L;
    List p1,p2,tail;
    p1 = L1->Next;//跳过头结点到达首元结点
    p2 = L2->Next;//同上
  if(p1&&p2){ /*存在L1,L2两个链表*/
          for(;p1&&p2;){
               if(p1->Data < p2->Data){
               tail = p1->Next; //记录下一个
               p1->Next = NULL; //把p1当前指向节点与后面节点断开
               p3->Next = p1;   //把L链表的当前节点指向需要添加的节点 完成连接
               p3 = p3->Next;   //链表L的指针向前移动
               p1 = tail;       //p1在指向L1链表原来节点的下一个
               }else if(p1->Data > p2->Data){
               tail = p2->Next; //重复使用
               p2->Next = NULL;
               p3->Next = p2;
               p3 = p3->Next;
               p2 = tail;
               }else{
                   tail = p1->Next;
                   p1->Next = NULL;
                   p3->Next = p1;
                   p3 = p3->Next;
                   p1 = tail;
                   tail = p2->Next;
                   p2->Next = NULL;
                   p3->Next = p2;
                   p3 = p3->Next;
                   p2 = tail;
               }

          } 
  }
  if(p1)
  {
    for(;p1;){
        if(p3->Data <= p1->Data &&p3->Next==NULL){
        tail = p1->Next;
        p3->Next = p1;
        p3 = p3->Next;
        p3->Next = NULL;
        p1 = tail;
        }else {
            printf("Fair");
        }
    }
  }
  
  if(p2){
      for(;p2;){
     if(p3->Data <= p2->Data&&p3->Next==NULL){
         tail = p2->Next; //记住L2节点的下一个,节点要被移到L上
         p3->Next = p2;
         p3 = p3->Next; //P3指针前进移动至末尾 
         p3->Next = NULL; //将节点与原来链表L2的联系断开
         p2 = tail; //将p2指针移动回原来节点的下一个
     }else {
         printf("Fair!");
     }
      }
  }
    p1 = L1;
    p2 = L2;
    p1 ->Next = NULL;
    p2 ->Next = NULL;
   return L;
}

写的有些杂乱 语言来描述思路有点杂乱 下次争取用流程图来描述
如果有同学有不懂的问题 可以在评论区问我 我会及时回复你


  1. 属于只要懂链表知识 和足够的时间就能写出来 ↩︎

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 11
    评论
评论 11
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值