算法_第二次实验

题目:归并排序、快速排序、堆排序

在这里插入图片描述
时间复杂度&空间复杂度:
快速排序 及其时间复杂度和空间复杂度

#include <iostream>
#include <cstdlib>
#include <ctime>
using namespace std;
void swap(int &a, int &b);	// 交换 
void mergeSort(int num[],int left,int right);	// 归并排序 
void merge(int num[],int left,int right,int mid);	// 归并排序合并 
void quickSort(int num[], int left, int right);	// 快速排序 
int partition(int num[], int left, int right);	// 快速排序轴值 
void heapSort(int num[], int N);	// 堆排序
void heapify(int num[], int i, int N);	// 堆的维护
// 计算时间时,将数组输出具体数值去掉 
int main()
{
	int N,num[100000];
	clock_t start,finish;
	while (1) {
		srand((unsigned)time(NULL));
		cout<<endl<<"**********"<<endl;
		cout<<"输入问题规模:"<<endl;
		cin>>N;
		// 随机数 
		for (int i=0; i<N; i++) {
			num[i] = rand()%10000 + 1;	// 	max+1
		}
		// 输出
		cout<<"排序前:";
		for (int i=0; i<N; i++) {
			if (i%20 == 0) {
				cout<<endl;
			}
			cout<<num[i]<<" "; 
		}
		// 选择
		cout<<endl<<"归并排序选1,快速排序选2,堆排序选3:" <<endl;
		int choose;
		cin>>choose;
		switch(choose) {
			case 1 : {
				cout<<"归并排序";
				start = clock();
				mergeSort(num, 0, N-1);
				finish = clock();
				break;
			}
			case 2 : {
				cout<<"快速排序";
				start = clock();
				quickSort(num, 0, N-1);
				finish = clock();
				break;
			}
			case 3 : {
				cout<<"堆排序";
				start = clock();
				heapSort(num, N-1);
				finish = clock();
				break;
			}
			default : {
				cout<<"输入错误!!"<<endl; 
				return 0;
			}
		}
		cout<<"后:";
		for (int i=0; i<N; i++) {
			if (i%20 == 0) {
				cout<<endl;
			}
			cout<<num[i]<<" "; 
		}
		cout<<endl<<"时间为:"<<(double)(finish-start)/CLOCKS_PER_SEC<<"s"; 
	}
	return 0;
}
// 交换 
void swap(int &a, int &b)
{
	int z = a;
	a = b;
	b = z;
}
// 归并排序 
void mergeSort(int num[],int left,int right)
{
	if (left < right) {
		int mid =  (left + right)/2;
		mergeSort(num,left,mid);	// 递归划分左半区域	
		mergeSort(num,mid+1,right);	// 递归划分右半区域
		merge(num,left,right,mid);	// 合并
	}
}
// 归并排序合并 
void merge(int num[],int left,int right,int mid)
{
	int i=left;	// 标记左右未排序元素
	int j=mid+1;
	int num_[100000];	// 设置临时数组
	int i_= left; 
	// 合并 
	while (i <= mid && j <= right) {
		if (num[i] < num[j]) 
			num_[i_++] = num[i++]; 
		else
			num_[i_++] = num[j++];
	}
	// 一边先合并完,剩余另一边,直接放入 
	while (i <= mid) 
		num_[i_++] = num[i++]; 
	while (j <= right) 
		num_[i_++] = num[j++]; 
	// 把临时数组复制回原数组 
	while (left <= right) {
		num[left] = num_[left];
		left++;
	}
}
// 快速排序 
void quickSort(int num[], int left, int right)
{
	if (left < right) {
		int mid = partition(num, left, right);
		quickSort(num, left, mid-1);
		quickSort(num, mid+1, right);
	}
}
// 快速排序轴值 
int partition(int num[], int left, int right)
{
	// 设置左右指针
	int i = left;
	int j = right;
	// 设置默认轴值
	int pivot = num[right]; 
	while (i != j) {
		while (i < j && num[i] <= pivot) {
			i++;
		}
		while (i < j && num[j] >= pivot) {
			j--;
		}
		if (i != j) {
			swap(num[i], num[j]);
		}
	} 
	swap(num[i], num[right]); 
	return i;
}
// 堆排序 
void heapSort(int num[], int N)
{
	// 堆的维护:变成大顶堆,从末尾第一个父结点开始 
	for (int i=(N-1)/2; i>=0; i--) {
		heapify(num, i, N);
	}
	// 排序
	for (int i=N; i>0; i--) {
		swap(num[i], num[0]);
		heapify(num, 0, i-1);
	} 
}
// 堆的维护
void heapify(int num[], int i, int N)
{
	// 设i就是最大的
	int largest = i;
	// 左右孩子
	int lson = i*2+1;
	int rson = i*2+2;
	// 找这三个中最大的,下标放到largest里
	if (lson <= N && num[lson] > num[largest]) {
		largest = lson;
	} 
	if (rson <= N && num[rson] > num[largest]) {
		largest = rson;
	}
	if (largest != i) {
		swap(num[i], num[largest]);
		heapify(num, largest, N);
	}
	 
} 

运行时间与输入规模之间的关系曲线图:
在这里插入图片描述

根据曲线图,三种排序优劣:快速排序 > 堆排序 > 归并排序。
时间复杂度和空间复杂度:
归并排序、快速排序、堆排序都采用了分治法的思想,分治法是将问题分解为子问题,子问题分别求解再合并,涉及递归调用。
归并排序把一个规模为n的问题分解成两个规模为n/2的子问题解决,假设T(n)表示对n个数进行归并排序,则2T(n/2)表示将n个数分成两部分分别进行归并排序,分解子问题所花的时间是问题规模n,所以T(n)=2T(n/2)+n,时间复杂度为O(nlogn)。归并排序比较元素大小时,需要一个与待排序序列同样长度的存储空间来存放结果,所以空间复杂度为O(n)。
快速排序根据轴值分解子问题,最好的情况就是每一次取到的元素都刚好平分整个数组,扫描了整个待排序数组找到轴值,所需时间为n,所以2T(n/2)+n,总时间复杂度为O(nlogn)。最坏的情况就是每一次取到的元素是数组中最小/最大的,也就是冒泡排序,时间复杂度为:O(n^2)。快速排序空间复杂度为:O(logn)。
堆排序建堆的时间复杂度为O(n),给堆重新排序变成顺序数组的时间复杂度为O(nlogn),所以总的时间复杂度为O(n+nlogn)=O(nlogn)。堆排序是就地排序,空间复杂度为常数:O(1)。

题目:计数排序

在这里插入图片描述

#include <iostream>
#include <cstdlib>
#include <ctime>
using namespace std;
void swap(int &a, int &b);	// 交换
int countingSort(int num[], int N,int i);	// 计数排序 
void quickSort(int num[], int left, int right);	// 快速排序 
int partition(int num[], int left, int right);	// 快速排序轴值 
// 计算时间时,将输出的数值去掉 
int main()
{
	srand((unsigned)time(NULL));
	int N,i,num[100000];
	clock_t start,finish;
	while (1) {
		cout<<endl<<"**********"<<endl;
		cout<<"输入问题规模:"<<endl;
		cin>>N;
		cout<<"输入i:"<<endl;
		cin>>i;
		// 随机数 
		for (int j=0; j<N; j++) {
			num[j] = rand()%10000 + 2;
		}
		// 输出
		cout<<"排序前:"; 
		for (int j=0; j<N; j++) {
			if (j%20 == 0) {
				cout<<endl;
			}
			cout<<num[j]<<" "; 
		}
		cout<<endl<<"选择方法:"<<endl;
		cout<<"计数排序选择1,快速排序选择2:"<<endl;
		int input,z;
		cin>>input;
		switch(input) {
			case 1 :
				start = clock();
				z = countingSort(num, N, i);
				finish = clock();
				break;
			case 2 :
				start = clock();
				quickSort(num, 0, N-1);
				z = num[i-1];
				finish = clock();
				break;
			default :
				cout<<"输入错误!!"<<endl;
				return 0;
		} 
		cout<<"第"<<i<<"小的元素是:"<<z<<endl;
		cout<<"时间为:"<<(double)(finish-start)/CLOCKS_PER_SEC<<"s"; 
	}
	return 0;
}
// 交换 
void swap(int &a, int &b)
{
	int z = a;
	a = b;
	b = z;
}
// 计数排序
int countingSort(int num[], int N,int i)
{
	// 找出最大最小值 
	int max = num[0], min = num[0];
	for (int j=0; j<N; j++) {
		if (num[j] > max) {
			max = num[j];
		}
		if (num[j] < min) {
			min = num[j];
		}
	}
	// 设置数组 
	int num_[max-min+1] = {0};
	// 计数累加
	for (int j=0; j<N; j++) {
		num_[num[j]-min]++;
	}
	int k=0;
	while (i > 0) {
		i=i-num_[k++];
	}
	return k-1+min;
} 
// 快速排序 
void quickSort(int num[], int left, int right)
{
	if (left < right) {
		int mid = partition(num, left, right);
		quickSort(num, left, mid-1);
		quickSort(num, mid+1, right);
	}
}
// 快速排序轴值 
int partition(int num[], int left, int right)
{
	// 设置左右指针
	int i = left;
	int j = right;
	// 设置默认轴值
	int pivot = num[right]; 
	while (i != j) {
		while (i < j && num[i] <= pivot) {
			i++;
		}
		while (i < j && num[j] >= pivot) {
			j--;
		}
		if (i != j) {
			swap(num[i], num[j]);
		}
	} 
	swap(num[i], num[right]); 
	return i;
}

数据查找:
在这里插入图片描述

快速排序时间复杂度是O(nlogn)。
计数排序是建立一个新数组,遍历原数组,每一个旧元素按照其值对应新数组下标对号入座,新数组的元素进行加1操作。如果原数组的规模是N,最大最小整数的差值是M,也就是新数组长度为M,计数排序只涉及到数组的遍历,所以时间复杂度是O(N+M)。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值