【解题报告】《算法零基础100讲》(第36讲) 排序进阶 - 归并排序

前言

表面上复习一下归并排序,实际上做题都偷偷在用快排。。。

归并排序

原理

假设初始序列含有n个子序列, 每个子序列的长度为1, 然后两两归并,得到 n / 2个长度为2或1的有序子序列; 再两两归并,……, 如此重复, 直至得到一个长度为n的有序序列为止, 这种排序方法称为2-路归并排序

图示(非递归形式)

在这里插入图片描述
进行一一合并
在这里插入图片描述
二二合并
在这里插入图片描述

四四合并

在这里插入图片描述

八八合并
在这里插入图片描述

之后再根据数据多少继续合并,直至合并为一组且长度为n。

代码实现(带注释)

static void Merge(int* nums, int numsSize, int gap);

void Merge_Sort(int* nums, int numsSize)
{
	assert(nums != NULL);

	for (int i = 1; i < numsSize; i *= 2)
	{
		Merge(nums, numsSize, i);
	}
}

static void Merge(int* nums, int numsSize, int gap)
{
	//申请额外空间,等长于原始数组
	int* ans = (int*)malloc(sizeof(int) * numsSize);
	assert(ans != NULL);

	int i = 0; // 额外数组ans的下标

	//申请四个指针,用来表示合并两组的边界
	int low1 = 0;
	int high1 = low1 + gap - 1;
	int low2 = high1 + 1;
	int high2 = low2 + gap - 1 < numsSize ? low2 + gap - 1 : numsSize - 1;


	while (low2 < numsSize) // 当low2满足小于len,则low1和high1肯定满足条件
	{
		//比较两组数据
		while (low1 <= high1 && low2 <= high2)
		{
			if (nums[low1] <= nums[low2])
			{
				ans[i++] = nums[low1++];
			}
			else
			{
				ans[i++] = nums[low2++];
			}
		}

		//上面的while循环跳出
		//要么因为右边组数据比较完了,那就把
		//左边组剩下的数据也放下来
		while (low1 <= high1)
		{
			ans[i++] = nums[low1++];
		}
		//要么因为左边组数据比较完了,那就把
		//右边组剩下的数据也放下来
		while (low2 <= high2)
		{
			ans[i++] = nums[low2++];
		}

		//更新指针
		low1 = high2 + 1;
		high1 = low1 + gap - 1;
		low2 = high1 + 1;
		high2 = low2 + gap - 1 < numsSize ? low2 + gap - 1 : numsSize - 1;
	}

	//上面的外层循环跳出,可能存在这种情况
	//即右边组没有数据了,左边还有,则把左边数据放下来
	while (low1 < len)
	{
		ans[i++] = nums[low1++];
	}

	//再把排好序后的数据放回原始数组
	for (int j = 0; j < numsSize; ++j)
	{
		nums[j] = ans[j];
	}

	//再把额外空间释放掉
	free(ans);
	ans = NULL;
}


习题

164. 最大间距

原题链接:164. 最大间距
在这里插入图片描述

代码

今天复习的归并,那就用归并做

void MergeSort(int* nums, int numsSize);
void Merge(int* nums, int numsSize, int gap);

int maximumGap(int* nums, int numsSize)
{
    if (NULL == nums || numsSize < 2)
    {
        return 0;
    }

    MergeSort(nums, numsSize);

    int ans = 0, max = 0;
    for (int i = 0; i < numsSize - 1; ++i)
    {
        //printf("%d\n", nums[i]);
        max = nums[i + 1] - nums[i];
        ans = fmax(max, ans);
    }

    return ans;
}

void MergeSort(int* nums, int numsSize)
{
    for (int i = 1; i < numsSize; i *= 2)
    {
        Merge(nums, numsSize, i);
    }
}

void Merge(int* nums, int numsSize, int gap)
{
    int* ans = (int*)malloc(sizeof(int) * numsSize);

    int i = 0;

    int low1 = 0;
    int high1 = low1 + gap - 1;
    int low2 = high1 + 1;
    int high2 = low2 + gap - 1 < numsSize ? low2 + gap - 1 : numsSize - 1;

    while (low2 < numsSize)
    {
        while (low1 <= high1 && low2 <= high2)
        {
            if (nums[low1] <= nums[low2])
            {
                ans[i++] = nums[low1++];
            }
            else
            {
                ans[i++] = nums[low2++];
            }
        }

        while (low1 <= high1)
        {
            ans[i++] = nums[low1++];
        }
        while (low2 <= high2)
        {
            ans[i++] = nums[low2++];
        }

        low1 = high2 + 1;
        high1 = low1 + gap - 1;
        low2 = high1 + 1;
        high2 = low2 + gap - 1 < numsSize ? low2 + gap - 1 : numsSize - 1;
    }

    while (low1 < numsSize)
    {
        ans[i++] = nums[low1++];
    }

    for (int j = 0; j < numsSize; ++j)
    {
        nums[j] = ans[j];
    }

    free(ans);
    ans = NULL;
}

912. 排序数组

原题链接:912. 排序数组
在这里插入图片描述

代码

归并就按那套写没有多大问题,其他题目可以快排解决

class Solution {
public:
    vector<int> sortArray(vector<int>& nums)
    {
        sort(nums.begin(), nums.end());
        return nums;
    }
};

217. 存在重复元素

原题链接:217. 存在重复元素
在这里插入图片描述

代码

排序完再比较

int mycmp(const void* p1, const void* p2)
{
    const int* a = (const int*) p1;
    const int* b = (const int*) p2;

    return *a - *b;
}
bool containsDuplicate(int* nums, int numsSize)
{
    if (numsSize < 2)
    {
        return false;
    }

    qsort(nums, numsSize, sizeof(int), mycmp);

    for (int i = 0; i < numsSize - 1; ++i)
    {
        if (nums[i] == nums[i + 1])
        {
            return true;
        }
    }
   return false;
}

169. 多数元素

原题链接:169. 多数元素

在这里插入图片描述

代码

int cmp(const void* p1, const void* p2)
{
    const int* a = (const int*)p1;
    const int* b = (const int*)p2;
    return *a - *b;
}

int majorityElement(int* nums, int numsSize)
{
    if (NULL == nums || numsSize == 0)
        return 0;
    
    qsort(nums, numsSize, sizeof(int), cmp);

    return nums[numsSize / 2];
}

面试题 10.01. 合并排序的数组

原题链接:面试题 10.01. 合并排序的数组

在这里插入图片描述

代码

合并再排序

int cmp(const void* p1, const void* p2)
{
    const int* a = (const int*)p1;
    const int* b = (const int*)p2;
    return *a - *b;
}
void merge(int* A, int ASize, int m, int* B, int BSize, int n)
{
    if (NULL == A || NULL == B)
    {
        return ;
    }

    //合并
    for (int i = 0; i < n; ++i)
    {
        A[m + i] = B[i];
    }

    qsort(A, ASize, sizeof(int), cmp);
}

练习题

148. 排序链表

在这里插入图片描述

end

原文链接:《算法零基础100讲》(第36讲) 排序进阶 - 归并排序
作者:英雄哪里出来

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

_索伦

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值