前言
表面上复习一下归并排序,实际上做题都偷偷在用快排。。。
目录
归并排序
原理
假设初始序列含有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);
}
练习题
end
原文链接:《算法零基础100讲》(第36讲) 排序进阶 - 归并排序
作者:英雄哪里出来