<LeetCode OJ> 148. Sort List

本文介绍了一种链表归并排序算法的具体实现方法,该算法具有O(n log n)的时间复杂度和O(1)的空间复杂度。通过递归地将链表分为更小的部分并合并它们来达到排序的目的。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

148. Sort List

Total Accepted: 64927  Total Submissions: 268346  Difficulty: Medium

Sort a linked list in O(n log n) time using constant space complexity.


别人的分析:

能够有O(n*lg(n))时间复杂度的算法为

快速排序,堆排序,归并排序,三者的空间复杂度分别为O(1), O(n),O(n)

通常的,对数组而言,归并排序的空间复杂度为O(n), 你需要开出O(N)的额外空间来容纳数组,来表示归并后的顺序。但是,对于链表,你可以省下这部分空间的开销,你只需要改变节点的next指针的指向,就可以表示新的归并后的顺序了,所以空间复杂度陡然降到了O(1)。

时间复杂度:O(n*lg(n))

空间复杂度:O(1)

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    //一,对链表进行合并排序,并且返回其头指针
    ListNode *sortList(ListNode *head) {
        if(head == NULL) 
            return head;
        if(head -> next == NULL)
            return head;
        //寻找链表中间位置
        ListNode* fast = head;
        ListNode* slow = head;
        while(fast -> next != NULL && fast -> next -> next != NULL)
        {
            fast = fast -> next;
            fast = fast -> next;
            slow = slow -> next;
        }
        
        ListNode* mid = slow -> next;
        slow -> next = NULL;//截断成两段
        
        ListNode* list1 = sortList(head);//再划分
        ListNode* list2 = sortList(mid);
        
        ListNode* sorted = merge(list1 , list2);//划分到最底层后在合并
        return sorted;
    }
    
    //二,合并两个链表再返回其头指针
    ListNode* merge(ListNode* list1 , ListNode* list2){
        if(list1 == NULL) 
            return list2;
        if(list2 == NULL) 
            return list1;
        
        ListNode* head;
        ListNode* tmp;
        
        if(list1 -> val < list2 -> val){
            head = list1;
            list1 = list1 -> next;
        }else{
            head = list2;
            list2 = list2 -> next;
        }
        tmp = head;
        
        while(list1 != NULL && list2 != NULL){
            if(list1 -> val < list2 -> val){
                tmp -> next = list1;
                tmp = list1;
                list1 = list1 -> next;
            }else{
                tmp -> next = list2;
                tmp = list2;
                list2 = list2 -> next;
            }
        }
        if(list1 != NULL) 
            tmp -> next = list1;
        if(list2 != NULL) 
            tmp -> next = list2;
        
        return head;
    }
};




对比学习数组版本的归并:

时间复杂度:O(n*lg(n))

空间复杂度:O(lg(n))????

#include "windows.h"
#include "vector"  
#include <iostream>  
#include "fstream"
#include "algorithm"  
#include <stdio.h>
#include "string"
#include <cmath>
#include <cstdlib>
#include "map"

using namespace std;


//分治法的合并函数  ,将真正执行排序过程
//将数组A[low.....mid]和A[mid+1.......high]合并
void Merge(vector<int> &a, int low, int mid, int high)
{
	int n1 = mid - low + 1;//A[low.....mid]的长度
	int n2 = high - mid;//A[mid+1.......high]的长度
	long Max = 99999999;//烧饼元素的值
	int *L = new int[n1 + 1];//需要开辟额外控件(多申请一个烧饼位置)
	int *R = new int[n2 + 1];
	if (L == NULL || R == NULL)
		exit(1);
	
	int i = 0;
	for (; i < n1; i++)
		L[i] = a[low + i];

	int j = 0;
	for (; j < n2; j++)
		R[j] = a[mid + j + 1];

	i = 0; j = 0;
	int k = 0;
	
	L[n1] = Max;//哨兵元素位置    
	R[n2] = Max;
	//合并到数组a中
	for (k = low; k <= high; k++)
	{
		if (L[i] <= R[j])
		{
			a[k] = L[i];
			i++;
		}
		else
		{
			a[k] = R[j];
			j++;
		}
	}

	delete[] L;
	delete[] R;
}

//合并排序法(分治法)  
//将数组A[low......high]左排序,再右排序,最后合并成新的有序序列
void MergeSort(vector<int> &a, int low, int high)
{
	if (low < high)
	{
		int mid = (low + high) / 2;
		MergeSort(a, low, mid);
		MergeSort(a, mid + 1, high);
		Merge(a, low, mid, high);//合并成新的有序序列
	}
}

int main()
{
	int arr[10] = {2,3,6,1,0,2,4,5,6,9};
	vector<int> vec(arr,arr+10);
	MergeSort(vec,0,9);
	for (int i = 0; i <= 9; i++)
		cout << vec[i] << " ";
	system("pause");
	return 0;
}



注:本博文为EbowTang原创,后续可能继续更新本文。如果转载,请务必复制本条信息!

原文地址:http://blog.youkuaiyun.com/ebowtang/article/details/50349562

原作者博客:http://blog.youkuaiyun.com/ebowtang

本博客LeetCode题解索引:http://blog.youkuaiyun.com/ebowtang/article/details/50668895

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值