#include<iostream>
#include<vector>
#include<algorithm>
#include<time.h>
#include"queue.h"
#define MIN -9999
#define MAX 9999
using namespace std;
// 基于散列表的排序
/*01 桶排序*/
int* find_extremum(int* arr, int n) // 找数组中的极值(min,max)
{
int* res = new int[2]; // res[0]:min res[1]:max
/*int min = MIN, max = MAX;*/
int min = MAX, max = MIN;
for (int i = 0; i < n; ++i)
{
if (arr[i] > max) max = arr[i];
if (arr[i] < min) min = arr[i];
}
res[0] = min; res[1] = max;
return res;
}
int* find_extremum(vector<int>& arr, int n) // 函数重载
{
int* res = new int[2]; // res[0]:min res[1]:max
int min = MAX, max = MIN;
for (int i = 0; i < n; ++i)
{
if (arr[i] > max) max = arr[i];
if (arr[i] < min) min = arr[i];
}
res[0] = min; res[1] = max;
return res;
}
void bucket_sort(int* arr, int n) // assert: 每个桶重复的元素不是很多
{
int* min_max = find_extremum(arr, n);
int min = min_max[0], max = min_max[1];
int bucket_num = (max - min) / n + 1; // 由于 是向下取整,最后要加上1
vector<int>* bucket_array = new vector<int>[bucket_num]; // 每个桶装一个vector
for (int i = 0; i < n; ++i)
{
bucket_array[(arr[i] - min) / n].push_back(arr[i]);
}
for (int i = 0; i < bucket_num; ++i) {
if (bucket_array[i].empty()) continue; // 空桶直接跳过
sort(bucket_array[i].begin(), bucket_array[i].end());
}
int k = 0;
for (int i = 0; i < bucket_num; ++i) {
if (bucket_array[i].empty()) continue;
for (int j = 0; j < bucket_array[i].size(); ++j)
arr[k++] = bucket_array[i][j];
}
}
/*02 计数排序*/
void counting_sort(int* arr, int n) // assert: 重复较多,元素范围相对集中
{
int maxval = find_extremum(arr, n)[1];
int* count_array = new int[maxval + 1]; // [0...maxval,maxval+1)
memset(count_array, 0, (maxval+1) * sizeof(int)); // count_array 中每个元素初始化为 0
for (int i = 0; i < n; ++i)
{
count_array[arr[i]]++;
}
// 再次遍历count_array得到最终结果
int k = 0; // 基于散列表排序recycle的老套路
for (int i = 0; i < maxval+1; ++i)
{
while (count_array[i] > 0) {
arr[k++] = i;
count_array[i]--;
}
}
}
/*03 基数排序*/
queue<int> bucket_queue[10]; // 10个桶构成的数组,每个数组的元素是一个链队列
int get_digit(int* arr, int n) // 最大的关键字有几位
{
int max_num = find_extremum(arr, n)[1];
int cnt = 0;
while (max_num > 0)
{
max_num /= 10;
cnt++;
}
return cnt;
}
void radix_sort(int* arr, int n)
{
int digit = get_digit(arr, n);
for (int i = 1; i <= digit; ++i) // 外循环要做digit趟
{
// allocate
for (int j = 0; j < n; ++j) // 遍历数组
{
int index = 0; int digit_th = i;
int tmp = arr[j];
while (digit_th > 0)
{
index = tmp % 10;
tmp /= 10;
--digit_th;
}
bucket_queue[index].enqueue(arr[j]);
}
// recycle
int k = 0; ptr_node<int> ptr = nullptr; // 依然是老套路
for (int l = 0; l < 10; ++l) // 遍历桶
{
if (bucket_queue[l].empty()) continue;
for (ptr = bucket_queue[l].first(); ptr != bucket_queue[l].tail; ptr = ptr->suc)
arr[k++] = ptr->data;
bucket_queue[l].clear(); // 清空桶
}
}
}
/*04 应用:最大间隙问题*/
/*题目描述: 在x轴上插入n个点 (x1,0) (x2,0) ...(xn,0) 求这n个点当中最大间隙 注:最边缘的
两个区间(-oo,xi] [xj,+oo)不算做间隙,即最多有n-1个间隙*/
int find_max_gap(int* points, int n)
{
int* min_max = find_extremum(points, n);
int min = min_max[0], max = min_max[1];
if (min == max) return 0; // 退化情况
vector<int>* bucket_array = new vector<int>[n]; // n个桶
for (int i = 0; i < n; ++i)
{
int addr = (n - 1) * (points[i] - min) / (max - min); // 每个gap.len=(max-min)/(n-1) n个点,n-1个gap
bucket_array[addr].push_back(points[i]); // addr是基于此的简单地址映射
}
vector<vector<int>> bucket_arr_copy; // 清除空桶
for (int i = 0; i < n; ++i)
{
if (bucket_array[i].size() > 0)
bucket_arr_copy.push_back(bucket_array[i]);
}
int max_gap = 0;
// 找出每个bucket当中最大最小值
for (int i = 1,len=bucket_arr_copy.size(); i<len/*i < bucket_arr_copy.size()*/; ++i) // 细细品会
{
int* res1 = find_extremum(bucket_arr_copy[i - 1], bucket_arr_copy[i - 1].size());
int min1 = res1[0], max1 = res1[1];
int* res2= find_extremum(bucket_arr_copy[i], bucket_arr_copy[i].size());
int min2 = res2[0], max2 = res2[1];
if (min2 - max1 > max_gap) max_gap = min2 - max1; // 推导见教材p279
}
return max_gap;
}
void show(int* arr, int len)
{
for (int i = 0; i < len; ++i)
{
cout << arr[i] << " ";
}
cout << endl;
}
int main()
{
srand((unsigned)time(nullptr));
int arr[] = { 5,2,2,7,10,35,23,99,66,4,7};
int len = sizeof(arr) / sizeof(int);
/*01 bucket_sort*/
/*bucket_sort(arr, len);
cout << "after bucket_sort: ";
show(arr, len);*/
/*02 counting_sort*/
/*counting_sort(arr, len);
cout << "after counting_sort: ";
show(arr, len);*/
/*03 radix_sort*/
/*radix_sort(arr, len);
cout << "after radix_sort: ";
show(arr, len);*/
/*04 find_max_gap*/
int points[10] = { 0 };
for (int i = 0; i < 10; ++i) points[i] = (rand() % 200)-100;
int num = sizeof(points) / sizeof(int);
show(points, num);
int max_gap = find_max_gap(points, num);
cout << "max_gap = " << max_gap << endl;
cout << "after sort: ";
sort(points, points+num);
show(points, num);
}
内部排序(二)---基于散列表
最新推荐文章于 2022-10-28 16:24:52 发布