单词排序——一道招聘笔试题

正文

前几天参加一家公司的实习招聘,笔试中有一道题,是让对单词按字母进行排序。
单词结构体类似如下,其中word中的字符均在小写字母a~z范围内:

struct words{
    string word;
    word*next;
    ...
};

这是链表结构。
对链表的排序,如果是原址排序,一般复杂度都是 O(n2)
对于链表中的关键字——string类型的str,如果进行比较排序,每次都调用比较操作运算(如果是C语言,则是使用库函数strcmp进行比较),平均字符比较次数与单词长度相关(单词长度对时间复杂度的影响在这里未作深究)。

如果要取得 nlog(n) 的时间复杂度,必须先花费 O(n) 的时间将链表的每个元素复制到一个数组,再使用快排、堆排序等方法。

这里我使用一种类似基数排序的方法,可以使整个排序达到 O(n) 的时间复杂度。大致思路如下:

构造一个容器,一共26个槽,对应a~z的26个字母。对于链表中的每个单词,依据第i个字母:如果存在,放入对应的槽中;不存在,则增加屏蔽计数。然后对槽中数目超过1的递归上述过程。
c++代码如下:

void rescursort(vector<words*>&pwords, int idx = 0){
//pwords是存进vector的链表指针向量 idx 表示字母下标数
    vector<vector<words*>> ps(26);
    vector<words*> temp;
    int count = 0;
    for each (auto var in pwords)
    {
        if (var->word[idx] - 'a' >= 0)
            ps[var->word[idx] - 'a'].push_back(var);
        else{
            count++;
            temp.push_back(var);
        }
    }
    for (int i = 0; i < count; i++){
        pwords[i] = temp[i];
    }
    for (int i = 0; i < 26; i++){
        if (ps[i].size()>1){
            rescursort(ps[i], idx + 1);//
            for (int k = 0; k < ps[i].size(); k++){
                pwords[count++] = ps[i][k];
            }
        }
        else if (ps[i].size()){
            pwords[count++] = ps[i][0];
        }
    }
}
void sortwords(words*p){
    int count[26];
    vector<words*> ps;
    for (words*pc = p->next; pc; pc = pc->next){
        ps.push_back(pc);
    }
    rescursort(ps);
    words*prev = p;
    for (int k = 0; k<ps.size(); k++){
        prev->next = ps[k];
        prev = ps[k];
    }
    prev->next = NULL;
}

存取链表用时 O(2n)
递归共用时间 O(Ln) ,L是单词最大长度。
一共 O((2+L)n)

总结

这种方法对于大量长度较短且较均匀的字符序列或者多维数进行排序比较合适,但由于二维向量的使用,对于长度不确定或是比较长的关键字还是使用比较排序节省空间。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值