每日一练——xt的基数排序 (25 分)

167 阅读4分钟

一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第12天,点击查看活动详情。​​

题目概述:

大家都知道xt现在在备战北大,北大的复试是有上机的环节的,xt很怕会被复试筛掉,所以提前了一年时间在备战上机测试。今天在模拟测试的时候,前三道题xt分别用Python,C++,Java解决了,到了第四题,xt看时间很充足就想去吃个饭,所以xt把希望都寄托在你身上了,第四道是一道链表的题目,考察基数排序。

链式基数排序(这里以对若干个正整数的排序为例描述求解过程):待排序的正整数存放在一个单链表buf中。此外还需要10个单链表,编号为0~9。10个单链表称为10个桶。编写一个程序,读入n个正整数,并按从小到大的顺序排序。

链式基数排序的算法如下:遍历buf中的每个节点,并根据它的个位将每个值安排某个桶链表中。例如,97安排在桶链表7,3安排在桶链表3,而100安排在桶链表0——这个过程叫分派。

在桶链表中循环,并将值复制回到最初的buf链表——这个过程叫收集。上面的数值在buf中的新顺序是100、3和97。

接下来依次取buf链表中所有数字的十位,百位,千位等等,并按取出的十位,百位,千位等位上的数字不断分派和收集;重复这个过程(分派---收集),当处理完了buf链表中最大数字的最高位时,就停止这个过程。

例如,在对buf链表进行第2轮处理时,100安排在桶链表0,3安排在桶链表0(它仅有一个数位),而97安排在桶链表9。buf链表中值的顺序是97、3和100。在第3轮处理时,100安排在桶链表1,3安排在桶链表0,而97安排在桶链表0(在3之后)。基数排序可以确保在处理了最大数字的最高位之后正确排列所有值的顺序。

注意

为保持输出结果的一致性,我们约定所有单链表的插入都使用头插法。

输入格式:

第一行输入待排序个数n(1≤n≤100000),再输入n个正整数(每个数在C语言整型表示范围之内)。

输出格式:

输出每趟分派-收集后链表中的关键字,趟数为序列中最大值的数位(如样例中930的数位为3),每个数之间用空格隔开。

输入样例:

在这里给出一组输入。例如:

10
278 109 63 930 589 184 505 269 8 83

输出样例:

在这里给出相应的输出。例如:

930 83 63 184 505 8 278 269 589 109
505 8 109 930 63 269 278 83 184 589
8 63 83 109 184 269 278 505 589 930

题意

将一堆数字,以每个数位(个位十位百位..到最大数字的位数截至)的大小为顺序进行排序,当两个数字的某位数上的数字相同时,以后来的在前面进行排序。并按从低位到高位进行输出。

思路

  1. 首先算出最大数字的位数。
  2. 利用栈“先进后出”的特性,开一个二维栈,第一维表示数字的该数位的数字,并放进相应的下标的栈区。模拟前插法。
  3. 遍历栈并放入数组中,遍历数组输出即可。
  4. 进入下一个数位的排序,重复以上操作。

代码如下:

#include <cstring>
#include <algorithm>
#include <stack>
#include <vector>
#include <cmath>

using namespace std;

const int N = 1e5 + 10, M = 10;

int n;
vector<int> a;

int main()
{
    cin >> n;
    a.resize(n);
    
    int cnt = 1;
    for (int i = 0; i < n; i ++ )
    {
        cin >> a[i];
        cnt = max(cnt, int(to_string(a[i]).size()));//to_string()将整形数字转化为字符串,这样可以快速地得到a[i]的位数。
    }
    
    for(int i = 0; i < cnt; i++)
    {
        stack<int> num[M];
        for(int j = 0, x = pow(10, i); j < n; j++)
        {
            num[a[j] / x % 10].push(a[j]);//将对应位数放进对应下标的栈。
        }
        
        a.clear();
        for(int j = 0; j < M; j++)
        {
            while(num[j].size())
            {
                a.push_back(num[j].top());//将对应的栈顶元素按顺序放进a数组中。
                num[j].pop();//弹出栈顶元素。
            }
        }
        
        for(int x : a) {
            cout << x << ' ';//遍历输出。
        }
        
        reverse(a.begin(), a.end());
        puts("");
    }
    
    return 0;
}