链表的归并排序

news/2024/11/8 18:46:35 标签: 链表, 数据结构, 算法

两种方法
递归法(自顶向下法)

迭代法(自底向上法)

递归法(自顶向下法)

这里链表与数组不同的是链表无法随机访问,在数组中我们都能精准的找到中间位置,这里我们采用快慢指针来确定中间节点,然后通过递归到单个元素然后分割链表,再链接链表(下面将一一讲解)

快慢指针确定中间节点

/*head为已知条件*/
Listnode* tail=nullptr;
Listnode* slow=head;
Listnode* fast=head; 
while(fast!=tail)         //快指针多移动一次到尾时,慢指针则为中间节点
{ 
   slow=slow->next;
   fast=fast->next;
   if(fast!=tail)
   {
      fast=fast->next;
   }
   Listnode* mid=slow;    //中间节点
}

分割链表

ListNode* apart_list(ListNode* head,ListNode* tail)
{
    if(head==nullptr) return nullptr;
    if(head->next==tail) return head;
    Listnode* slow=head;
    Listnode* fast=head; 
    while(fast!=tail)         //快指针多移动一次到尾时,慢指针则为中间节点
    { 
       slow=slow->next;
       fast=fast->next; 
       if(fast!=tail)         //头闭尾开只有一个元素head 无法继续分割返回head节点 
       { 
          fast=fast->next;
       }
       Listnode* mid=slow;    //中间节点
    }
    
    /*这里的merge为合并函数*/
    /*我们这里递归分割左右链表,递归到只有一个元素无法分割后链接两边节点*/
    return merge(apart_list(head,mid),apart_list(mid,tail));
}
/*
    假如链表如下:
    1   4   3   5   2  
第一次分割1,nullptr中间节点为3 也就是  return merge(apart_list(1,3),apart_list(3,nullptr)) 
第二次分割1,3中间节点为2  然后 return  merge(apart_list(1,2),apart_list(2,3))   
第三次分割1,2无法进行分割 此时满足head->next=tail 1节点下一节点置空 返回1节点
第四次分割2,3同理 置空2节点的下一节点后返回2节点
然后通过执行merge(2,3)将分割的单个节点2和3有序链接  返回给上一级递归
同理3,nullptr也是如此
*/

链接链表

这个就简单了就是合并两个有序链表

 ListNode* merge(ListNode* l,ListNode* r)
{
   ListNode* temp=new ListNode(0);
   ListNode* l_now=l;
   ListNode* r_now=r;
   ListNode* now=temp;
   
   /*都有元素则比较大小*/
   while(l_now!=nullptr&&r_now!=nullptr)
   {
      if(l_now->val<=r_now->val)
      {
          now->next=l_now;
          l_now=l_now->next;
      }  
      else 
      {
          now->next=r_now;
          r_now=r_now->next;
      }
      now=now->next;
   }
   
   /*链接剩下的元素*/
   if(l_now!=nullptr)
   {
       now->next=l_now;
   }
   else now->next=r_now;
   return temp->next;
}

完整代码

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode() : val(0), next(nullptr) {}
 *     ListNode(int x) : val(x), next(nullptr) {}
 *     ListNode(int x, ListNode *next) : val(x), next(next) {}
 * };
 */
class Solution {
public:
    ListNode* apart_list(ListNode* head,ListNode* tail)
    {
        if(head==nullptr) return nullptr;
        if(head->next==tail)
        {
            head->next=nullptr;
            return head;
        }
        ListNode* slow=head,*fast=head;
        while(fast!=tail)
        {
            slow=slow->next;
            fast=fast->next;
            if(fast!=tail)
            {
                fast=fast->next;
            }
        }
        ListNode* mid=slow;
        return merge(apart_list(head,mid),apart_list(mid,tail));
    }
    ListNode* merge(ListNode* l,ListNode* r)
    {
        ListNode* temp=new ListNode(0);
        ListNode* l_now=l;
        ListNode* r_now=r;
        ListNode* now=temp;
        while(l_now!=nullptr&&r_now!=nullptr)
        {
            if(l_now->val<=r_now->val)
            {
                now->next=l_now;
                l_now=l_now->next;
            }
            else
            {
                now->next=r_now;
                r_now=r_now->next;
            }
            now=now->next;
        }
        if(l_now!=nullptr)
        {
           now->next=l_now;
        }
        else if(r_now!=nullptr)
        {
           now->next=r_now;
        }
        return temp->next;
    }
    ListNode* sortList(ListNode* head) {
        return apart_list(head,nullptr);
    }
};

时间复杂度为O(nlogn)空间复杂度为O(logn)

自底向上法

和数组一样我们需要不断的增加分区间的距离

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode() : val(0), next(nullptr) {}
 *     ListNode(int x) : val(x), next(nullptr) {}
 *     ListNode(int x, ListNode *next) : val(x), next(next) {}
 * };
 */
class Solution {
public:
    ListNode* sortList(ListNode* head) {
        if(head==nullptr)
        {
            return head;
        }
        int length=0;
        ListNode* node=head;
        while(node!=nullptr)
        {
            length++;
            node=node->next;
        } 
        ListNode* temp=new ListNode(0,head);
        for(int len=1;len<length;len*=2)     //增加半区间
        {
            ListNode* pre=temp,*now=temp->next;
            while(now!=nullptr)
            {
                ListNode* head1=now;
                for(int i=1;i<len&&now->next!=nullptr;i++)
                {
                    now=now->next;
                }
                ListNode*head2=now->next;
                now->next=nullptr;            //分割
                now=head2;
                for(int i=1;i<len&&now!=nullptr&&now->next!=nullptr;i++)
                {
                    now=now->next;
                }
                ListNode* next=nullptr;
                if(now!=nullptr)
                {
                    next=now->next;
                    now->next=nullptr;
                }
                ListNode* marged=merge(head1,head2);
                pre->next=marged;
                while(pre->next!=nullptr)
                {
                    pre=pre->next;
                }
                now=next;
            } 
        }
        return temp->next;
    }
    ListNode* merge(ListNode* l,ListNode* r)
    {
        ListNode* temp=new ListNode(0);
        ListNode* l_now=l;
        ListNode* r_now=r;
        ListNode* now=temp;
        while(l_now!=nullptr&&r_now!=nullptr)
        {
            if(l_now->val<=r_now->val)
            {
                now->next=l_now;
                l_now=l_now->next;
            }
            else
            {
                now->next=r_now;
                r_now=r_now->next;
            }
            now=now->next;
        }
        if(l_now!=nullptr)
        {
           now->next=l_now;
        }
        else if(r_now!=nullptr)
        {
           now->next=r_now;
        }
        return temp->next;
    }
};

时间复杂度为O(logn)空间复杂度为O(n)


http://www.niftyadmin.cn/n/5744297.html

相关文章

8+ 典型分析场景,25+ 标杆案例,Apache Doris 和 SelectDB 精选案例集(2024版)电子版上线

当前&#xff0c;各企业正面临前所未有的数据增量&#xff0c;不仅体现在数据规模的急剧上升&#xff0c;还体现在数据的类型多样性和产生速度的加快。数据体量大固然蕴藏着更大的潜力及可能性&#xff0c;但如何有效利用这些数据&#xff0c;解决实际问题、赋能业务增长&#…

夜天之书 #103 开源嘉年华纪实

上周在北京参与了开源社主办的 2024 中国开源年会。其实相比于有点明显班味的“年会”&#xff0c;我的参会体验更像是经历了一场中国开源的年度嘉年华。这也是在会场和其他参会朋友交流时共同的体验&#xff1a;在开源社的 COSCon 活动上&#xff0c;能够最大限度地一次性见到…

ArcGIS地理空间平台 manager 任意文件读取漏洞复现

0x01 产品描述&#xff1a; ‌ ArcGIS‌是一个综合的地理空间平台&#xff0c;由Esri开发&#xff0c;旨在为专业人士和组织提供全面的地理信息系统&#xff08;GIS&#xff09;功能。ArcGIS通过集成和连接地理环境中的数据&#xff0c;支持创建、管理、分析、映射和共享…

Spring Boot驱动的导师双选系统:设计与实现

第一章 绪论 1.1 选题背景 如今的信息时代&#xff0c;对信息的共享性&#xff0c;信息的流通性有着较高要求&#xff0c;尽管身边每时每刻都在产生大量信息&#xff0c;这些信息也都会在短时间内得到处理&#xff0c;并迅速传播。因为很多时候&#xff0c;管理层决策需要大量信…

安全工程师入侵加密货币交易所获罪

一名高级安全工程师被判犯有对去中心化加密货币交易所的多次攻击罪&#xff0c;在此过程中窃取了超过 1200 万美元的加密货币。 沙克布艾哈迈德&#xff08;Shakeeb Ahmed&#xff09;被判刑&#xff0c;美国检察官达米安威廉姆斯&#xff08;Damian Williams&#xff09;称其…

[全网最细数据结构完整版]第六篇:3分钟带你吃透栈并模拟实现

目录 1->栈的概念和结构 1.1栈的概念 1.2栈的结构 2->栈的实现 2.1定义关于栈的结构体和各种函数 2.2栈的初始化 STInit 函数 2.3栈的销毁 STDestroy 函数 2.4栈的插入操作 STPush 函数 2.5栈的判断是否为空操作 STEmpty 函数 2.6栈的删除操作 STPop 函数 2.7…

vue2组件封装和UI组件的二次封装,方法,属性,ref的传递

封装组件使用v-model 使用方法props接受value值&#xff0c;当值发生变化的时候再通过this.$emit("input", newValue)&#xff0c;则实现了简单组件的v-model封装,如果不使用第三方UI可以接受到的值使用watch或者计算属性保存&#xff0c;然后再通过事件派发自己保存…

AI 重塑软件开发:流程、优势、挑战与应对

一、流程与模式介绍【传统软件开发 VS AI 参与的软件开发】 传统软件开发流程与模式 传统的软件开发是一个复杂且严谨的过程&#xff0c;通常遵循一系列既定的步骤。 需求分析&#xff1a; 开发团队与客户或相关利益者紧密合作&#xff0c;详细了解软件需要实现的功能、性能要…