归并排序和快速排序比较

最近在做一个算法实验:归并排序和快速排序的比较。

这两种算法在排序方面是非常非常的通俗的了,权威的文献和网上的相关文章也是一大堆,在这里就简单贴下代码,写下个人从这个实验中学到的东西。

先说说个人对这两个算法的理解:

归并排序,简单来说就是先将数组不断细分成最小的单位,然后每个单位分别排序,排序完毕后合并,重复以上过程最后就可以得到排序结果。

快速排序,简单来说就是先选定一个基准元素,然后以该基准元素划分数组,再在被划分的部分重复以上过程,最后可以得到排序结果。

两者都是用分治法的思想,不过最后归并排序的合并操作比快速排序的要繁琐。


下面是实验题目:

实验任务:

(1)用C/C++语言编程实现归并排序算法6.3 和快速排序算法6.6。对于快速排序,SPLIT中的划分元素采用三者A(low),A(high),A((low+high)/2)中其值居中者。

(2)随机产生20组数据(比如n=5000i,1≤i≤20)。数据均属于范围(0,105)内的整数。对于同一组数据,运行快速排序和归并排序算法,并记录各自的运行时间(以毫秒为单位)。

(3)根据实验数据及其结果来比较快速排序和归并排序算法的平均时间,并得出结论。

代码如下:

#include <iostream>
#include <time.h>
#define random(x) (double)rand() / RAND_MAX * 100000
using namespace std;

int *a_merge, *a_quick, *b;
int n;
int merge_count;
int quick_count;


/
//                         计时部分                                        //
/

/* 停止计时,并输出运行时间和比较次数
 * flag = 0代表归并排序
 * flag = 1代表快速排序
 */
void stop_clock(clock_t start_t, int flag)
{
	char *name  = (flag == 0) ? "归并排序"  : "快速排序";
	int compare = (flag == 0) ? merge_count : quick_count;

	clock_t stop_t = clock();
	double time = stop_t - start_t;
	cout<<endl;
	cout<<name;
	cout<<"排序用时:"<<time<<"ms"<<endl;
	cout<<"比较次数:"<<compare<<endl;
}


/
//                         基本函数                                        //
/

/* 输出数组a的内容 */
void output(int *a)
{
	cout<<"数组a为:"<<endl;
	for(int i = 0; i < n; i++)
	{
		cout<<a[i]<<" ";
	}
	cout<<endl;
}

/* 生成n个随机数 */
void randomGeneration(int n)
{
	a_merge = new int[n];
	a_quick = new int[n];
	b = new int[n];
	srand((int)time(0));
	for(int i = 0; i < n; i++)
	{
		a_merge[i] = random(100000);
		a_quick[i] = a_merge[i];
	}
}


/
//                         合并排序                                        //
/

/* 合并数组操作 */
void MERGE(int *a, int *b, int low, int mid, int high)
{
	for(int k = low; k <= high; k++)
	{
		b[k] = a[k];
	}

	int s1 = low, s2 = mid + 1, t = low;
	while(s1 <= mid && s2 <= high)
	{
		if(b[s1] <= b[s2])
		{
			a[t++] = b[s1++];
		}
		else
		{
			a[t++] = b[s2++];
		}
		merge_count++;
	}

	while(s1 <= mid)
	{
		a[t++] = b[s1++];
	}

	while(s2 <= high)
	{
		a[t++] = b[s2++];
	}
}

/* 归并排序 */
void mergesort(int *a, int *b, int low, int high)
{
	if(low >= high)
	{
		return;
	}

	int mid = (low + high) / 2;
	mergesort(a, b, low, mid);
	mergesort(a, b, mid + 1, high);
	MERGE(a, b, low, mid, high);
}

void my_mergesort()
{
	/* 运行归并排序算法, 并输出运行时间 */
	clock_t start_merge = clock();
	merge_count = 0;
	mergesort(a_merge, b, 0, n - 1);
	stop_clock(start_merge, 0);
}


/
//                         快速排序                                        //
/

/* 交换a[i]和a[j]的值 */
void exchange(int *a, int i, int j)
{
	int temp;
	temp = a[i];
	a[i] = a[j];
	a[j] = temp;
}

/* 设置用于划分的标准元素 */
void setReference(int *a, int low, int high)
{
	quick_count += 2;
	int mid = (low + high) / 2;
	if(a[mid] < a[high])
	{
		if(a[low] < a[mid]) // a[low] < a[mid] < a[high]
		{
			exchange(a, low, mid);
		}
		else if(a[low] < a[high]) // a[mid] < a[low] < a[high]
		{
			
		}
		else // a[mid] < a[high] < a[low]
		{
			exchange(a, low, high);
		}
	}
	else
	{
		if(a[mid] < a[low]) // a[high] < a[mid] < a[low]
		{
			exchange(a, low, mid);
		}
		else if(a[low] > a[high]) // a[high] < a[low] < a[mid]
		{

		}
		else // a[low] < a[high] < a[mid]
		{
			exchange(a, low, high);
		}
	}
}

/* 分割数组 */
int split(int *a, const int low, const int high)
{
	int temp = 0;
	// setReference(a, low, high);
	int refer = a[low];
	int i = low;
	for(int j = low + 1; j <= high; j++)
	{
		if(a[j] <= refer)
		{
			i++;
			// exchange(a, i, j);
			temp = a[i];
			a[i] = a[j];
			a[j] = temp;
		}
		quick_count++;
	}
	exchange(a, i, low);
	return i;
}

/* 快速排序 */
void quicksort(int *a, int low, int high)
{
	if(low < high)
	{
		int pos = split(a, low, high);
		quicksort(a, low, pos - 1);
		quicksort(a, pos + 1, high);
	}
}

void my_quicksort()
{
	/* 运行快速排序算法, 并输出运行时间 */
	clock_t start_quick = clock();
	quick_count = 0;
	quicksort(a_quick, 0, n - 1);
	stop_clock(start_quick, 1);
}


/
//                         主函数                                          //
/

/* 主函数 */
int main()
{
	int i, ch;
	char choose = 'y';
	while(choose == 'Y' || choose == 'y')
	{
		cout<<"请选择"<<endl;
		cout<<"1.手动输入i, 生成一组i * 5000个随机数"<<endl;
		cout<<"2.随机生成20组数据"<<endl;
		cin>>ch;
		if(ch == 1)
		{
			/* 输入整数i, 1 <= i <= 20 */
			cout<<"请输入整数i, 1 <= i <= 20:";
			cin>>i;
			if(i <= 0 || i >= 21)
			{
				cout<<"输入出错"<<endl;
			}
			else
			{
				/* 生成n个随机数, n = 5000 * i, 每个随机数的范围在0到10^5之间 */
 				n = 5000 * i;
				randomGeneration(n);

				/* 归并排序 */
				my_mergesort();

				/* 快速排序 */
				my_quicksort();
			}
		}
		else if(ch == 2)
		{
			for(i = 1; i < 21; i++)
			{
				cout<<"-----------------------------------"<<endl;
				n = 5000 * i;
				cout<<n<<"个数排序结果:"<<endl;
				randomGeneration(n);
				my_mergesort();
				my_quicksort();
			}
		}
		else
		{
			cout<<"输入出错"<<endl;
		}

		/* 是否循环? */
		cout<<endl<<"是否继续?y/n:";
		cin>>choose;
	}
	return 0;
}

实验结果:



当数据量越来越大时,

归并排序:比较次数少,速度慢。

快速排序:比较次数多,速度快。

快速排序的优势越来越明显。


原因分析:个人认为是当数据量越来越大时,尽管归并排序的比较次数较少,但是归并排序后期的合并操作所花费的时间便越来越大,合并操作对整体的效率影响越来越明显,包括后面大量数据的赋值操作等。所以当数据量变大时,不需要专门合并的快速排序的优势就变得越发明显。


那么我从这个实验学到了什么?

代码中快速排序的split函数代码如下:

/* 分割数组 */
int split(int *a, const int low, const int high)
{
	int temp = 0;
	// setReference(a, low, high);
	int refer = a[low];
	int i = low;
	for(int j = low + 1; j <= high; j++)
	{
		if(a[j] <= refer)
		{
			i++;
			// exchange(a, i, j);
			temp = a[i];
			a[i] = a[j];
			a[j] = temp;
		}
		quick_count++;
	}
	exchange(a, i, low);
	return i;
}

修改成:

/* 分割数组 */
int split(int *a, const int low, const int high)
{
	int temp = 0;
	// setReference(a, low, high);
	int refer = a[low];
	int i = low;
	for(int j = low + 1; j <= high; j++)
	{
		if(a[j] <= refer)
		{
			i++;
			exchange(a, i, j);
			/*
			temp = a[i];
			a[i] = a[j];
			a[j] = temp;
			 */
		}
		quick_count++;
	}
	exchange(a, i, low);
	return i;
}

也就是将交换操作变成函数调用方法。再Run一下看看:


在100000个数的情况下快速排序居然比修改前的程序慢了接近20ms。这个问题困扰了我好久,我之前一直都找不出为什么我的程序中快速排序比归并排序要慢,原因就在这里。

这也是我从这个算法中学到的最重要的东西:频繁的函数调用大大降低了算法的效率。

看来函数是不能滥写的,这可能会大大降低程序运行效率,以后必须多加注意。


  • 41
    点赞
  • 79
    收藏
    觉得还不错? 一键收藏
  • 9
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值