小菜鸟的算法导论学习笔记——分治排序

        分治排序的特点在于每次都将要排序的对象分成两部分,再考虑将这两部分进行排序,排序过程是自下而上的,即先排序分到最后只剩单个元素的两个对象,再逐渐向上,一旦理解了这一点,就可以写出如下的分治排序过程伪代码:

//MERGE-SORT
merge_sort(A,p,q)//p和q分别指A的下限和上限取值
    {
        if (q>p)//说明分治没有到最底层
        {
            r = (q+p)/2;
            merge_sort(A,p,r);
            merge_sort(A,r+1,q);
            merge(A,p,q,r);//这里的第一层是指,假设p~r与r+1~q都排序好的情况下,对这两大块进行排序。实际运行中,第一个运行该函数的是最底层的单独两个元素,单个元素不存在排序好的情况,如此往上迭代
        }
    }
  

        在这里本人纠结了很久merge_sort到底是什么含义的函数,其实实际上不用想那么多,它就相当于是一个方便我们将其拆分为两个部分,并且不断套娃的工具而已w。

        在最后分解为只剩单个元素了,merge_sort函数停止套娃,因为if语句判断为false,因此不执行任何操作。此时看向上一级,需要执行merge函数,merge函数是用来将这两部分进行排序,如此往上。

        以下是merge函数的伪代码:

merge(A,p,q,r)
{
    定义两个与A相同类型的数组/向量 M,N;
    将A下标为p~r的元素复制到M
    将A下标为r+1~q的元素复制到N

    //注意,M、N的实际大小要比上述大1,最后用来存储极限值(INT_MAX),称为哨兵牌
    
    int m = 0, n =0;
    for (int x = p ; x < q + 1 ; ++ x )
        if (M[m] <= N[n])
        {
            A[x]=M[m];
            ++m;
        }
        else 
        {
        A[x] = N[n];
        ++n;
        }
//因为一共有p-q+1个数字要进行排序,因此进行这么多次for循环后,所有数字可以排序完毕

}

        至此已经完成算法的逻辑描述。下面是应用案例:

#include <iostream>
#include <string>
#include <vector>
using namespace std;


//MERGE-SORT 分治排序

//merge_sort函数负责将一个数组/向量分割成两部分,merge函数负责将两个数组/向量整合
//p和q指A的上下限,p为下限,q为上限

void merge(vector<int>& A, int p, int q, int r)
{
	vector<int> M(r - p + 1 + 1);
	int m=0, n = 0;
	for (int i = p; i < r + 1; ++i)
	{
		M[m] = A[i];
		++m;
	}
	M[r - p + 1] = INT_MAX;

	vector<int> N(q - r  + 1);
	for (int i = r + 1; i < q + 1; ++i)
	{
		N[n] = A[i];
		++n;
	}
	N[q - r] = INT_MAX;

	int m_2 = 0, n_2 = 0;
	for (int i = p; i < q + 1; ++i)
	{
		if (M[m_2] <= N[n_2])
		{
			A[i] = M[m_2];
			++m_2;
		}
		else
		{
			A[i] = N[n_2];
			++n_2;
		}

	}
}

void merge_sort(vector<int> &A,int p, int q)
{
	if (q > p)
	{
		int r = (p + q) / 2;
		merge_sort(A, p, r);
		merge_sort(A, r + 1, p);

		//对A中,p~r和r+1~q两大块进行排序,默认的条件是这两大块都已经排好了顺序,在程序中,这一行是最后一次执行的merge。
		//当A向量分解到了最后一层,即只有一个元素,这个时候就是2个独立的元素合成一个包含2个元素的向量,如此向上——4个、8个...
		merge(A, p, q, r);
	}
}


int main()
{
	vector<int> vector_test;
	int num_of_vec = 0,input = 0;
	cout << "输入vector的大小" << endl;
	cin >> num_of_vec;
	cout << "依次输入vector的每个值" << endl;
	//也可以根据num_of_vec创造这个大小的vector
	for (int size = 0; size < num_of_vec; ++size)
	{
		cin >> input;
		vector_test.push_back(input);
	}


	merge_sort(vector_test, 0, num_of_vec-1);
	for (int i = 0; i < num_of_vec; ++i)
	{
		cout << vector_test[i] << " ";
	}

	return 0;
}

个人想法:

1、由于对个人而言涉及到的局部变量较多,因此调试时出现了很多问题。在思考的时候要想清楚,局部变量要放在哪里合适,放在函数体内部的变量要尤其谨慎!

2、自从简单学习了vector之后感觉比数组好用多了好吧qwq,使用体验完全碾压数组哈哈哈

3、更进一步地,为了提高效率,有时候发现当有一端出现了哨兵牌(或不使用哨兵牌时发现所有数字都被拷贝走了)时,可以直接停止for循环。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值