PTA Insert or Merge 思路分析及代码解析

一、前导

1. 需要掌握的知识

插入排序、归并排序的非递归实现

2. 题目信息

  1. 题目来源:PTA
  2. 题目地址:Insert or Merge

二、解题思路分析

1. 题意理解

根据N趟排序后的元素序列(N是未知数)推断出使用的排序算法,随后打印N+1趟排序后的元素序列。题目中使用的排序算法是插入排序或归并排序

1. 1 输入数据

10  //待排序元素个数
3 1 2 8 7 5 9 4 6 0 //待排序元素序列
1 2 3 7 8 5 9 4 6 0 //经过N趟排序后的元素序列

1.2 输出数据

Insertion Sort	//根据“经过N趟排序后的元素序列”,识别出使用的排序算法
1 2 3 5 7 8 9 4 6 0 //打印N+1趟排序后的元素序列

2. 思路分析

  1. 本题AC的关键:正确实现插入排序 和 归并排序(非递归)
  2. 每经过一趟排序,对排序后的结果 和 预期结果(经过N趟排序后的元素序列) 进行对照,若结果一致,打印对应的排序算法名称
  3. 再进行一趟排序,随后打印排序后的元素序列

三、具体实现

1. bug和弯路

执行排序算法后,注意恢复数据

2. 代码框架(重点)

2.1 采用的数据结构

使用数组

2.2 程序主体框架

               程序伪码描述
int main()
{
	1.将输入数据存入数组中
	2.分别执行插入排序和归并排序,每进行一趟排序,执行一次比对
}

2.3 各分支函数

2.3.1 InsertSortAndJudge( ) 插入排序算法,实现起来比较容易,注意比较和打印的时机即可

void InsertSortAndJudge(int a[], int b[], int N)
{
	int i, j,tmp;

	for (i = 1; i < N; i++) //抽一张牌
	{
		tmp = a[i];
		
		//从后向前检索已排序序列,找到合适的插入位置
		for (j = i; j > 0 && a[j - 1] > tmp; j--) 
			a[j] = a[j - 1];

		a[j] = tmp; //插入

		if (flag)
		{
			int k = 0; cout << a[k];
			for (k = 1; k < N; k++)
				cout << " " << a[k];
			return;
		}
		
		if (Judge(a, b, N))
		{
			flag = true;
			cout << "Insertion Sort" << endl;
		}		
	}

	return;
}

2.3.2 Merge( )函数:将数组a分为两部分[Left,Right-1] 、[Right,RightEnd],然后按从小到大的规则对这两部分进行排序,将排序结果存储到数组b中,Merge( )被Merge_Pass( )调用

void Merge(int a[], int b[], int Left, int Right, int RightEnd)
{
	int ArrayNumber= RightEnd-Left+1;//数组a的元素个数  //数组a 数组b元素个数相同
	int LeftEnd = Right - 1; //将数组a分为两部分
	int index=Left;//数组b的初始索引值 = 数组a的首元素索引值

	while (Left <= LeftEnd && Right <= RightEnd)
	{
		if (a[Left] <= a[Right])
			b[index++] = a[Left++];
		else
			b[index++] = a[Right++];
	}
	while (Left <= LeftEnd)
		b[index++] = a[Left++];
	while (Right <= RightEnd)
		b[index++] = a[Right++];

	return;
}

2.3.3 Merge_Pass( ) : 归并排序算法的子函数, Merge_Pass( )对相邻的两个有序子列进行合并。Merge_Pass( ) 理解起来还是蛮难的 囧

//两两归并相邻有序子列。tmp是归并排序算法中创建的数组,大小为N,同数组a
//Length是有序子列的长度,初始值为1
void Merge_Pass(int a[], int tmp[], int N, int Length)
{
	int i, j;

	//N - 2*Length 是为了确保每次Merge,一定有两个有序子列
	for (i = 0; i <= N - 2 * Length; i = i + 2 * Length) //Hard!!
		Merge(a, tmp, i, i + Length, i + 2 * Length - 1); 

	if (i + Length < N) //归并最后2个子列
		Merge(a, tmp, i, i + Length, N - 1);
	else //只有一个子列了
		for (j = i; j < N; j++)
			tmp[j] = a[j];
}

2.3.4 MergeSortAndJudge 归并排序的非递归算法它每次的排序位于Merge_Pass( )的调用后,打印时注意区分 原始数组和临时存储数组 哪一个存储当前趟排序后的数据

void MergeSortAndJudge(int a[], int b[], int N)
{
	int Length = 1;//归并子序列初始长度为1
	int tmp[MAX];

	while (Length < N)
	{
		Merge_Pass(a, tmp, N, Length);
		Length *= 2;

		if (flag)
		{
			cout << tmp[0];
			for (int i = 1; i < N; i++)
				cout<<" " << tmp[i];
			return;
		}

		if (Judge(tmp, b, N))
		{
			flag = true;
			cout << "Merge Sort" << endl;
		}	

		Merge_Pass(tmp, a, N, Length);
		Length *= 2;

		if (flag)
		{
			cout << a[0];
			for (int i = 1; i < N; i++)
				cout << " " << a[i];
			return;
		}

		if (Judge(a, b, N))
		{
			flag = true;
			cout << "Merge Sort" << endl;
		}
	}

	return;
}

3. 完整编码

#include <iostream>
using namespace std;

#define MAX 100

void Merge_Pass(int a[], int tmp[], int N, int Length);
void Merge(int a[], int b[], int Left, int Right, int RightEnd);
void MergeSortAndJudge(int a[], int b[], int N);
void InsertSortAndJudge(int a[],int b[], int N);
bool Judge(int a[], int b[], int N);

bool flag = false; //

int main()
{
	int Origin[MAX], Sorting[MAX],Bak[MAX];
	int N;
	cin >> N;
	
	for (int i = 0; i < N; i++)
	{
		cin >> Origin[i];
		Bak[i]= Origin[i];
	}	

	for (int i = 0; i < N; i++)
		cin >> Sorting[i];

	MergeSortAndJudge(Origin,Sorting, N);

	if (flag)
		return 0;

	for (int i = 0; i < N; i++)
		Origin[i] = Bak[i];

	InsertSortAndJudge(Origin, Sorting, N);
	
	return 0;
}

void MergeSortAndJudge(int a[], int b[], int N)
{
	int Length = 1;//归并子序列初始长度为1
	int tmp[MAX];

	while (Length < N)
	{
		Merge_Pass(a, tmp, N, Length);
		Length *= 2;

		if (flag)
		{
			cout << tmp[0];
			for (int i = 1; i < N; i++)
				cout<<" " << tmp[i];
			return;
		}

		if (Judge(tmp, b, N))
		{
			flag = true;
			cout << "Merge Sort" << endl;
		}	

		Merge_Pass(tmp, a, N, Length);
		Length *= 2;

		if (flag)
		{
			cout << a[0];
			for (int i = 1; i < N; i++)
				cout << " " << a[i];
			return;
		}

		if (Judge(a, b, N))
		{
			flag = true;
			cout << "Merge Sort" << endl;
		}
	}

	return;
}

//两两归并相邻有序子列
//tmp是归并排序算法中创建的数组,大小为N,同数组a
//Length是有序子列的长度,初始值为1
void Merge_Pass(int a[], int tmp[], int N, int Length)
{
	int i, j;

	//N - 2*Length 是为了确保每次Merge,一定有两个有序子列
	for (i = 0; i <= N - 2 * Length; i = i + 2 * Length) //Hard!!
		Merge(a, tmp, i, i + Length, i + 2 * Length - 1); 

	if (i + Length < N) //归并最后2个子列
		Merge(a, tmp, i, i + Length, N - 1);
	else //只有一个子列了
		for (j = i; j < N; j++)
			tmp[j] = a[j];
}

//将数组a分为两部分[Left,Right-1],[Right,RightEnd]
//按从小到大的规则,对这两部分进行排序,将结果存放到数组b
void Merge(int a[], int b[], int Left, int Right, int RightEnd)
{
	
	int ArrayNumber= RightEnd-Left+1;//数组a的元素个数  //数组a 数组b元素个数相同
	int LeftEnd = Right - 1; //将数组a分为两部分
	int index=Left;//数组b的初始索引值 = 数组a的首元素索引值

	while (Left <= LeftEnd && Right <= RightEnd)
	{
		if (a[Left] <= a[Right])
			b[index++] = a[Left++];
		else
			b[index++] = a[Right++];
	}
	while (Left <= LeftEnd)
		b[index++] = a[Left++];
	while (Right <= RightEnd)
		b[index++] = a[Right++];

	return;
}

void InsertSortAndJudge(int a[], int b[], int N)
{
	int i, j,tmp;

	for (i = 1; i < N; i++)
	{
		tmp = a[i];

		for (j = i; j > 0 && a[j - 1] > tmp; j--) //从后向前
			a[j] = a[j - 1];

		a[j] = tmp;

		if (flag)
		{
			int k = 0; cout << a[k];
			for (k = 1; k < N; k++)
				cout << " " << a[k];
			return;
		}
		
		if (Judge(a, b, N))
		{
			flag = true;
			cout << "Insertion Sort" << endl;
		}		
	}

	return;
}

bool Judge(int a[], int b[], int N)
{
	for (int i = 0; i < N; i++)
		if (a[i] != b[i])
			return false;

	return true;
}

四、参考

  1. 浙江大学 陈越、何钦铭老师主讲的数据结构
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值