#include<bits/stdc++.h>
typedef long long int ll;
//ceil() 向上取整
//sqrt()平方根
const int N = 11100;
using namespace std;
ll D[N] = { 0 };//待排序数组
ll MAX = 0, MIN = N;
ll m = 0;//待排序数组的变化范围
ll upintm = 0;//m开方向上取整
ll kw[N][N] = { 0 };//数组D的下标
int p, q;//p商,q余数
list <ll> link[N];//链接数组
ll n;//记录总个数
bool veri_upintm;//判断输入的数组是否相同
void read_value(ll *D)//读入数据并计算最大值最小值
{
int i = 1;//i从1开始变化,否则在链表赋值时无法区分第一个数重复和无重复的情况
while (cin >> D[i])
{
if (D[i] == '#')//‘#’输入结束标志
break;
MAX = D[i] > MAX ? D[i] : MAX;
MIN = D[i] < MIN ? D[i] : MIN;
i++;
}
n = i - 1;//i在循环中多增一次,总数量比i少一
}
//求解m与upm
void calculate_m_upintm(ll &m, ll &upintm)
{
m = MAX - MIN;
upintm = ceil(sqrt(m));
}
//开辟upintm行upintm列的数组kw,一维链接数组link[n],并对kw和link数组进行初始化
void init_kw_link(ll kw[N][N], list <ll> *link)
{
for (int i = 0; i <= upintm; i++)
{
for (int j = 0; j <= upintm; j++)
{
kw[i][j] = -1;//初始值为-1
}
}
for (int i = 1; i <= n; i++)
{
link[i].push_back(-1);//初始值为-1
}
}
bool verify_upintm()//判断数据是否全部相同
{
if (upintm == 0)
return false;
return true;
}
void showD()//输出数组
{
for (int i = 1; i <= n; i++)
cout << D[i] << ' ';
}
void quick_sort(ll *D, ll kw[N][N], list <ll> *link)
{
//计算每个D[i]与MIN的差对于upintm的商p和余数q
for (int i = 1; i <= n; i++)
{
p = (D[i] - MIN) / upintm;
q = (D[i] - MIN) % upintm;
if (p != upintm)
{
//把D[i]的下标i放到kw的第p行第q列的位置,并赋值link[i]=0,否则链接起来
if (kw[p][q] == -1)//如果还没有赋值,说明商p余q只有一个数字,把序号放在kw里
{
kw[p][q] = i;
link[i].pop_back();//原来的-1出栈
link[i].push_back(0);//0入栈
}
else//如果已经有值,则替换kw[p][q]位置的序号,将第i个link赋值原来kw的值
{
int temp = kw[p][q];
kw[p][q] = i;
link[i].pop_back();//原来的-1出栈
link[i].push_back(temp);//被替换掉的kw的坐标入栈,用link记录,起索引作用
}
}
else //如果p的值和平方m向上取整相等则跳过该数,根据计算,该数刚好是最大值
{
continue;
}
}
int k = 1;//新数组的下标
for (int p = 0; p <= upintm; p++)//此处ij从0开始,因为商和余数可以为0
{
for (int q = 0; q <= upintm; q++)
{
//从商0余0开始重新对D[]赋值,得到的新数组就是排序后的数组
if (kw[p][q] == -1)//说明没有商p余q的输入,该位置为空,不需要复制转下一个位置
{
continue;
}
else if (kw[p][q] != -1 && link[kw[p][q]].back() == 0)//表示kw[i][j]只对应D[]中的一个关键字,即同商同余只有一个
{
D[k] = p * upintm + q + MIN;
/*
对 p = (D[i] - MIN) / upintm;
q = (D[i] - MIN) % upintm; 的还原*/
k++;//第k位使用之后,开始填充下一个位置
}
else if (kw[p][q] != -1 && link[kw[p][q]].back() != 0)//表示D[]中有多个相同的关键字
{
//同商同余说明是相同的数字
D[k] = p * upintm + q + MIN;
k++;
int h = link[kw[p][q]].back();//h用来存放link[i]中连接的上一个相同数的位置
//将相同的数放入数组中,有多少个重复的就赋值多少次
do
{
D[k] = p * upintm + q + MIN;
k++;
h = link[h].back();
} while (h != 0);//循环跳出条件是link[i]中的数为0,即该数第一次出现的位置
}
}
}
int flag = 0;//记录是否有输出过数组D[N]
while (1)
{
if (k > n)
{
showD();
flag = 1;
}
else
{
D[k] = MAX;
k++;
/*在对kw操作时跳过了等于最大值的数,简化计算,直接把这些值放在最后即可
即跳过了p==upintm的数
m=MAX-MIN;
upintm=√(m*m);
MAX=MIN+upintm*upintm;
*/
}
if (flag)//如果成功输出则跳出循环
break;
}
}
int main()
{
system("color F0");//白底黑字
cout << "请输入待排序的整数,每个数之间用空格分开,以‘#’作为输入结束标志:" << endl;
read_value(D);//读入数组D[]
cout << "共输入了" << n << "个数" << endl;
calculate_m_upintm(m, upintm);//计算数据的差值m与m平方开放向上取整的upintm
veri_upintm = verify_upintm();//判断upintm的合法性,是否可以作为被除数
if (veri_upintm)//如果可以作为被除数,则进行排序操作
{
init_kw_link(kw, link);//对数组kw与链表数组link赋初值
cout << "排序后:" << endl;
quick_sort(D, kw, link);
}
else
showD();//因为一组数据相同,可直接输出数组
return 0;
}
/*
输入1:
23 4 21 28 23 4 10 15 26 25 15 23 8 10 9 28 17 3 24 3 20 14 26 13 18 25 7 19 26 23 #
输出1:
3 3 4 4 7 8 9 10 10 13 14 15 15 17 18 19 20 21 23 23 23 23 24 25 25 26 26 26 28 28
输入2:
-1 -1 -2 -3 -85 #
输出2:
-85 -3 -2 -1 -1
输入3:
10000 100000 10000000 1000 10 1 #
输出3:
1 10 1000 10000 100000 10000000
输入4:
5 5 5 5 5 #
输出4:
5 5 5 5 5
输入5:
584598 84569852 2962586 84126523 523 7426510 520 9520 8563 01749 #
输出5:
520 523 1749 8563 9520 584598 2962586 7426510 84126523 84569852
输入6:
-1 -85 -5623 -52 94865132 8465 5 #
输出6:
-5623 -85 -52 -1 5 8465 94865132
*/
【数据结构课程设计】基于商和余数的快速排序
最新推荐文章于 2025-05-02 22:13:06 发布