数据结构和算法笔记4:排序算法-归并排序

归并排序算法完全遵循分治模式。直观上其操作如下:

  • 分解:分解待排序的n个元素的序列成各具n/2个元素的两个子序列。
  • 解决:使用归并排序递归地排序两个子序列。
  • 合并:合并两个已排序的子序列以产生已排序的答案。

我们直接来看例子理解算法的过程,下面是要排序的数组,总共8个元素,我们划分为左右两个数组L和R(L和R都已经是有序的),L是原数组左边4个元素,R是原数组右边4个元素,为了让排序终止,两个数组的末尾加了一个无穷,用k指针指向原数组第一个元素2,i指针指向L数组第一个元素2,j指针指向R数组第一个元素1:

在这里插入图片描述

比较i指针所指2和j指针所指1:j指针所指1更小,k指针对应第一个元素赋值为1,j和k指针右移。
在这里插入图片描述

比较i指针所指2和j指针所指2:一样大,k指针对应第2个元素赋值为2,i和k指针右移。
在这里插入图片描述

比较i指针所指4和j指针所指2:j指针所指2更小,k指针对应第3个元素赋值为2,j和k指针右移。
在这里插入图片描述
如此做下去,直到i和j指针都遍历到最后:

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

对于上面的逻辑我们可以写作一个函数叫merge,它的目的是合并两个有序数组为一个新的有序数组,它的伪代码是:

在这里插入图片描述

其中A是一个数组,p、q和r是数组下标,满足p≤q<r。该过程假设子数组A[p.q]和A[q+1,r]都已排好序。它合并这两个子数组形成单一的已排好序的子数组并代替当前的子数组A[p.r]。

用C++实现一下:

void merge(std::vector<int>& A, int p, int q, int r)
{
   
   
	int n1 = q - p + 1;
	int n2 = r - q;
	std::vector<int> L(n1, 0);//[p,q]
	std::vector<int> R(n2, 0);//[q+1,r]
	for (int i = 0; i < n1; ++i)
		L[i] = A[p + i];
	for (int i = 0; i < n2; ++i)
		R[i] = A[q + i - 1];
	int i = 0;
	int j = 0;
	for (int k = p; k <= r; ++k)
	{
   
   
		if (i == n1)
		{
   
   
			A[k] = R[j];
			j++;
		}
		else if (j == n2)
		{
   
   
			A[k] = L[i];
			i++;
		}
		else if (L[i] <= R[j])
		{
   
   
			A[k] = L[i];
			i++;
		}
		else
		{
   
   
			A[k] = R[j];
			j++;
		}
	}
}

这样我们可以得到自底向上的排序:
在这里插入图片描述

算法的伪代码是:
在这里插入图片描述

void mergeSort(std::vector<int> &A, int p, int r)
{
   
   
    if (p < r)
    {
   
   
        int q = (p + r) / 2;
        mergeSort(A, p, q);
        mergeSort(A, q + 1, r);
        merge(A, p, q, r);
    }
}

测试代码:

int main()
{
   
   
    std::vector<int> A({
   
   1, 3
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值