左神算法基础class2—题目7、8桶排序之计数排序及其应用

1.计数排序

假设共有15个数,范围为(0-9),不用比较把所有数排好。

介绍

1.计数排序是一个非基于比较的排序算法与被排序的样本的实际数据状况很有关系,所
以实际中并不经常使用
2.时间复杂度O(N),额外空间复杂度O(N)
3.稳定的排序

分析

1.准备长度与数值范围相同的桶——10个桶(数值0-9)
2.遍历数组,数值为a时,把桶内位置为a的数加一
3.重构数组

核心代码

遍历:a[]是辅助数组,作为桶用来统计次数;arr[i]是原始数组。把原始数组的值作为桶的序号位置,桶在此位置的值加一。

	for(int i = 0;i < arr_Length;i++)
	{
		a[arr[i]]++;
	}

完整代码

#include <iostream>
using namespace std;
#include<time.h>
#define arr_Length 15


int main()
{
	//生成随机数
	srand((unsigned)time(NULL));
	int arr[arr_Length];
	cout << "原数组arr: ";
	for(int i = 0;i < arr_Length;i++)
	{
		arr[i] = rand()%10;
		cout << arr[i]<< ' ';
	}
	cout << endl <<endl;

	//准备桶 O(n)
	int a[arr_Length] = {0};

	//遍历O(n)
	for(int i = 0;i < arr_Length;i++)
	{
		a[arr[i]]++;
	}

	//重构O(n)
	for(int i = 0;i < arr_Length;i++)
	{
		if(a[i] != 0)
			cout<<a[i]<<"个"<<i<<endl;
	}

	system("pause");
	return 0;
}

2.应用:给定一个数组,求如果排序之后,相邻两数的最大差值,要求时间复杂度O(N),且要求不能用非基于比较的排序。【随机生成9个数,范围在0-99】

分析

1.假设共有N个数,准备N+1个桶。遍历找到数组的最小值和最大值,分别放在0位置和最后一个位置。将数组中最大值和最小值之间的值分为N+1等分(N+1个桶)。
2.准备三个长度为N+1的数组,分别为num_max[],num_min[] ,num_empty[]。表示当前位置桶内的最大值、最小值和桶是否为空。再把数组填入N+1个桶中,更新最大值、最小值。填完后必然存在一个空桶(N+1个桶,N个数)。
3.从1号桶开始,如果桶为空则继续下一个,若桶非空找前一个非空桶的最大值和当前桶的最小值求差值。遍历过后最大值即为所求。
Tips1:不能只找空桶两边的数,虽然同一桶内的差值小于空桶之间的差值,但是空桶两侧不一定为最大值。eg假设10个为桶的范围 19 (10-19) | 空(20-29) | 30(30-39) | 49(40-49),此时最大值为19。
Tips1:若max==min 所有数组值一样返回0。

核心代码

1.找出整个数组的min和max

int min = arr[0];
	int max = arr[0];
	for(int i = 0;i<length;i++)
	{
		min = arr[i] < min ? arr[i] : min;
		max = arr[i] > max ? arr[i] : max;
	}

2.最小值最大值为min、max时,把min、max之间的数划分为N+1个桶,当前数值存在a号桶内。

a = (arr[i]-min)*(length+1) / (max-min+1)

理解:
(1)(max-min+1)指最大值最小值之间有多少个,(length+1) 指桶的长度,(max-min+1)/(length+1) 指把之间的数平分。当前数arr[i]再除以平分的值,分母翻上去就是上式。
(2)左神课上代码 a = (arr[i]-min)*(length) / (max-min);调试的时候不对。
eg 数组长度9,桶长度10,最大值99,最小值0,应该分为10组,0-9,10-19…90-99,左神的代码会出问题。此外,max-min+1如果不加1的话感觉更符合实际情况,但是调试会出错。当数为99时,(99-0)×10/(99-0) = 10,即第11个位置,数组长度为10会溢出,此处还需要大神解释下。

3.更新桶内最大值和最小值

桶为空有数入桶时直接将当前数赋给桶内最值。

bool num_empty[length+1] = {0};
	int num_max[length+1] = {0};
	int num_min[length+1] = {0};

	for(int i = 0;i<length;i++)//对所有的数循环不是对所有桶循环不能length+1
	{
		int a = (arr[i]-min)*(length+1) / (max-min+1);
		
		if(num_empty[a] == 0)
		{
			num_max[a] = arr[i];
			num_min[a] = arr[i];
			num_empty[a] = 1;
		}
		num_max[a] = arr[i]>num_max[a]?arr[i]:num_max[a];
		num_min[a] = arr[i]<num_min[a]?arr[i]:num_min[a];
		
	}

4.求最大差值

最大差值是前一个桶的最大值到当前桶最小值内产生。首先将0号桶最大值记录,再从1号位置开始遍历,只遍历非空的桶,再更新最大差值及前一个桶的最大值,用作下次比较。

int res = 0;//最大差值
	int last_max = num_max[0];
	for(int i = 1;i < length + 1;i++)
	{
		if(num_empty[i])
		{
			res = (num_min[i] - last_max) < res ? res: (num_min[i] - last_max);
			last_max = num_max[i];
		}
	}

辅助代码:

void print(int arr[],int max,int min,int num_max[],int num_min[],bool num_empty[])
{
	cout<<"arr: ";
	for(int i = 0;i < length ;i++)
	{
		cout<<arr[i]<<" ";
	}
	cout<<endl<<"max= :"<<max<<"    "<<"min= :"<<min<<endl;
	cout<<"num_max:";
	for(int i = 0;i < length+1 ;i++)
	{
		cout<<num_max[i]<<" ";
	}
	cout<<endl<<"num_min:";
	for(int i = 0;i < length+1 ;i++)
	{
		cout<<num_min[i]<<" ";
	}
	cout<<endl;
}

完整代码

#include<iostream>
#include<time.h>
#define length  9
using namespace std;

//输出可视化
void print(int arr[],int max,int min,int num_max[],int num_min[],bool num_empty[])
{
	cout<<"arr: ";
	for(int i = 0;i < length ;i++)
	{
		cout<<arr[i]<<" ";
	}
	cout<<endl<<"max= :"<<max<<"    "<<"min= :"<<min<<endl;
	cout<<"num_max:";
	for(int i = 0;i < length+1 ;i++)
	{
		cout<<num_max[i]<<" ";
	}
	cout<<endl<<"num_min:";
	for(int i = 0;i < length+1 ;i++)
	{
		cout<<num_min[i]<<" ";
	}
	cout<<endl;
}

//
int maxgap(int arr[])
{
	//找出整个数组的min和max
	int min = arr[0];
	int max = arr[0];
	for(int i = 0;i<length;i++)
	{
		min = arr[i] < min ? arr[i] : min;
		max = arr[i] > max ? arr[i] : max;
	}
	if(max == min)
		return 0;
	bool num_empty[length+1] = {0};
	int num_max[length+1] = {0};
	int num_min[length+1] = {0};

	for(int i = 0;i<length;i++)//对所有的数循环不是对所有桶循环不能length+1
	{
		int a = (arr[i]-min)*(length+1) / (max-min+1);
		
		if(num_empty[a] == 0)
		{
			num_max[a] = arr[i];
			num_min[a] = arr[i];
			num_empty[a] = 1;
		}
		num_max[a] = arr[i]>num_max[a]?arr[i]:num_max[a];
		num_min[a] = arr[i]<num_min[a]?arr[i]:num_min[a];
		
	}
	print(arr,max,min,num_max,num_min,num_empty);
	int res = 0;
	int last_max = num_max[0];
	for(int i = 1;i < length + 1;i++)
	{
		if(num_empty[i])
		{
			res = (num_min[i] - last_max) < res ? res: (num_min[i] - last_max);
			last_max = num_max[i];
		}
	}
	return res;
}

int main()
{
	//生成随机数组
	int arr[length] ;
	srand((unsigned)time(NULL));
	for(int i = 0;i<length;i++)
	{
		arr[i] = rand()%100;
	}

	cout<<"maxgap=:"<<maxgap(arr);

	system("pause");
	return 0;
}

结果

随便放了两组随机生成的数
输出
在这里插入图片描述

发布了51 篇原创文章 · 获赞 1 · 访问量 1393

猜你喜欢

转载自blog.csdn.net/shi_xiao_xuan/article/details/103564471
今日推荐