Loading

力扣147.148排序链表--复习插入、归并和快速排序

插入排序

插入排序就是对当前元素从头搜索其在已排好序列表中的合适位置。

//升序
void InsertSort(vector<int>& nums)
{
	int len = nums.size();
	for(int i=0;i<len;i++)
	{
		int cur = nums[i];
		//已经排好序的最后一个位置
		int last = i-1;
		while(last >= 0 && nums[last] > cur)
		{
			//向后挪动数组
			nums[last+1] = nums[last];
			last--;
		}
		//当nums[last] <= cur --> cur 的位置是last+1
		nums[last+1] = cur;
	}
}

链表的插入排序

由于链表是由指针决定下一个元素,所以不会涉及到覆盖操作,但需要维持一个插入位置前的指针。

ListNode* InsertSort(ListNode* head)
{
	if(head == nullptr || head->next == nullptr) return head;
	ListNode* dummy = new ListNode(-1,head);
	//已排序好数组的最后一个元素
	ListNode* sorted = head;
	//待排序元素
	ListNode* cur = head->next;
	while(cur)
	{
		//如果sorted的值<=cur 说明cur在合适的位置
		if(sorted->val <= cur->val)
		{
			sorted = sorted->next;
		}
		//从头搜索cur的位置
		else
		{
			ListNode* pre = dummy;
			sorted->next = cur->next;
			//在已排序的链表中寻找最后一个小于cur的节点
			while(pre->next && pre->next->val <= cur->val)
			{
				pre = pre->next;
			}
			cur->next = pre->next;
			pre->next = cur;
		}
		cur = sorted->next;
	}
	return dummy->next;
}

递归的归并排序

归并排序主要流程是拆分 -- 排序 -- 合并 -- 排序 -- 合并

//拆分
void mergeSort(vector<int>& nums,int start, int end)
{
	if(start>=end) return ;
	int mid = start+(end-start)/2;
	mergeSort(nums,start,mid);
	mergeSort(nums,mid+1,end);
	//最后一层排序
	merge(nums,start,mid,end);
}
//排序
void merge(vector<int>& nums,int start, int mid, int end)
{
	vector<int> temp(end-start+1);
	int p1 = start;
	int p2 = mid+!;
	int p = 0;
	while(p1<=mid && p2<=end)
	{
		if(nums[p1] < nums[p2])
		{
			temp[p++] = nums[p1++];
		}
		else
		{
			temp[p++] = nums[p2++];
		}
	}
	while(p1<=mid)
	{
		temp[p++] = nums[p1++]; 
	}
	while(p2<=end)
	{
		temp[p++] = nums[p2++];
	}
	for(int i = 0;i<temp.size();i++)
	{
		nums[i] = temp[i];
	}
}
//实际调用
void sort(vector<int>& nums)
{
	mergeSort(nums,0,nums.size()-1);
}

对于链表的递归归并排序

最主要的就是如何找到中间节点,可以利用快慢指针来寻找中间节点,然后在mergeSort函数中记录中间节点的下一个节点,然后断开mid->next = nullptr;

class Solution {
public:
    //寻找中点
    ListNode* FindMid(ListNode* head)
    {
        if(head == nullptr) return nullptr;
        //快慢指针
        ListNode* fast = head->next;
        ListNode* slow = head;
        while(fast && fast->next)
        {
            fast = fast->next->next;
            slow = slow->next;
        }
        return slow;
    }
    //合并
    ListNode* merge(ListNode* left,ListNode* right)
    {
        ListNode* dummy = new ListNode(-1,left);
        ListNode* cur = dummy;
        while(left && right)
        {
            if(left->val < right->val)
            {
                cur->next = left;
                left = left->next;
            }
            else
            {
                cur->next = right;
                right = right->next;
            }
            cur = cur->next;
        }
        while(left)
        {
            cur->next = left;
            left = left->next;
            cur = cur->next;
        }
        while(right)
        {
            cur->next = right;
            right = right->next;
            cur = cur->next;
        }
        return dummy->next;
    }
    //归并排序
    ListNode* mergeSort(ListNode* head)
    {
        //当为空或者只有一个节点时直接返回
        if(head == nullptr || head->next == nullptr)
        {
            return head;
        }
        //寻找中间节点
        ListNode* mid = FindMid(head);
        ListNode* next = mid->next;
        //断开分段
        mid->next = nullptr;
        //划分
        ListNode* left = mergeSort(head);
        ListNode* right = mergeSort(next);

        //合并
        return merge(left,right);
    }
public:
    ListNode* sortList(ListNode* head) {
        return mergeSort(head);
    }
};

快速排序

冒泡排序基础上使用了递归分治法,快速排序在每一轮挑选一个基准元素,并让其他比它大的元素移到数列一边,比他小的移动到另一边,进行拆解。

void quicksort(vector<int>& nums,int left,int right)
{
  if(left >= right) return;
  int l = left-1;
  int r = right+1;
  //基准
  int mid = nums[left+right >> 1];
  while(l < r)
  {
    while(nums[++l]<mid);
    while(nums[--r]>mid);
   if(l<r) swap(nums[l],nums[r]);
  }
quicksort(nums,left,r);
quicksort(nums,r+1,right);
}

快速排序链表

/**
 * 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* FindMid(ListNode* head)
    {
        //if(head == nullptr || head->next == nullptr) return head;
        ListNode* fast = head;
        ListNode* slow = head;
        while(fast && fast->next)
        {
            fast= fast->next->next;
            slow = slow->next;
        }
        return slow;
    }
    ListNode* quickSort(ListNode* head)
    {
        if(head == nullptr || head->next == nullptr) return head;
        //3组指针:小于 等于 大于 基准值的边界节点
        ListNode* leftmin = new ListNode(-1);
        ListNode* rightmin = leftmin;
        ListNode* lefteq = new ListNode(-1);
        ListNode* righteq = lefteq;
        ListNode* leftmax = new ListNode(-1);
        ListNode* rightmax = leftmax;

        ListNode* cur = head;
        //选择中间节点为基准
        int pivot = FindMid(head)->val;

        while(cur)
        {
            //记录当前分段头节点的下一个节点
            ListNode* next = cur->next;

            //当当前分段的第一个值小于当前分段的基准,截断
            //更新小于的区间
            if(cur->val < pivot)
            {
                cur->next = nullptr;
                rightmin->next = cur;
                rightmin = rightmin->next;
            }
            else if(cur->val > pivot)
            {
                cur->next = nullptr;
                rightmax->next = cur;
                rightmax = rightmax->next;
            }
            else
            {
                cur->next = nullptr;
                righteq->next = cur;
                righteq = righteq->next;
            }
            //对下一个节点开始判断
            cur = next;
        }
        //对小于和大于的链表快排
        leftmin = quickSort(leftmin->next);
        leftmax = quickSort(leftmax->next);

        //leftmin 可能为空
        lefteq = lefteq->next;
        righteq->next = leftmax;
        if(leftmin == nullptr) return lefteq;
        else
        {
            rightmin = leftmin;
            while(rightmin->next)
            {
                rightmin = rightmin->next;
            }
            rightmin->next = lefteq;
            return leftmin;
        }
    }
public:
    ListNode* sortList(ListNode* head) {
        return quickSort(head);
    }
};
posted @   XTG111  阅读(20)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
点击右上角即可分享
微信分享提示