数据结构与算法面试:基于比较的排序算法时间复杂度最坏情况下是 O(nlogn),请问有没有更快的算法?(提示:计数排序、基数排序)

简介: 数据结构与算法面试:基于比较的排序算法时间复杂度最坏情况下是 O(nlogn),请问有没有更快的算法?(提示:计数排序、基数排序)

数据结构与算法面试:基于比较的排序算法时间复杂度最坏情况下是 O(nlogn),请问有没有更快的算法?(提示:计数排序、基数排序)

简介:基于比较的排序算法时间复杂度最坏情况下是 O(nlogn),请问有没有更快的算法?(提示:计数排序、基数排序)

基数排序是一种时间复杂度O(nlogn)的排序算法,其中d是数组a中最大数字的位数。如果数字长度d较小,那么基数排序要比比较排序更快。

基数排序的实现思路如下:

  1. 用一个桶数组来记录每个可能的数字出现的次数(这里假设数值范围在0~9之间)。
  2. 将原始数组a依次按照个位、十位、百位、千位…进行排序。对于某个"当前位数"可以采用计数排序或者桶排序的方式,在该轮排序后,原始数组a已经被排好序了。

下面是使用C++实现基数排序的代码,并附带详细注释:

#include <iostream>
#include <vector>
using namespace std;
void radix_sort(vector<int>& a) {
    int n = a.size();
    if (n <= 1) return;
    // 获取数组中的最大值
    int max_val = a[0];
    for (int i = 1; i < n; ++i) {
        max_val = max(max_val, a[i]);
    }
    // 计算出最大值的长度
    int k = 0;
    while (max_val > 0) {
        max_val /= 10;
        ++k;
    }
    // 建立桶数组并进行基数排序
    vector<int> bucket(a.size());
    vector<int> count(10);
    // 每一轮循环按照不同的位数进行排序
    for (int i = 0, r = 1; i < k; ++i, r *= 10) {
        // 将桶清零
        fill(count.begin(), count.end(), 0);
        // 统计出现次数
        for (int j = 0; j < n; ++j) {
            int c = (a[j] / r) % 10;
            ++count[c];
        }
        // 计算前缀和
        for (int j = 1; j <= 9; ++j) {
            count[j] += count[j - 1];
        }
        // 按顺序将数放到桶中
        for (int j = n - 1; j >= 0; --j) {
            int c = (a[j] / r) % 10;
            bucket[--count[c]] = a[j];
        }
        // 从桶中取回数据
        for (int j = 0; j < n; ++j) {
            a[j] = bucket[j];
        }
    }
}
int main() {
    vector<int> a = {7, 6, 5, 4, 3, 2, 1, 0};
    radix_sort(a);
    for (int i = 0; i < a.size(); ++i) {
        cout << a[i] << " ";
    }
    cout << endl;
    return 0;
}

该算法借助"桶"和"计数"两种数据结构,实现了时间复杂度O(dn)的基数排序算法。为了方便地处理数组中的数字,我们可以将其转换为字符串然后进行操作。

  • java
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
class Main {
    public static void radixSort(int[] a) {
        int n = a.length;
        if (n <= 1) return;
        // 获取数组中的最大值
        int max_val = a[0];
        for (int i = 1; i < n; ++i) {
            max_val = Math.max(max_val, a[i]);
        }
        // 计算出最大值的位数
        int k = 0;
        while (max_val > 0) {
            max_val /= 10;
            ++k;
        }
        // 建立桶数组并进行基数排序
        int[] bucket = new int[a.length];
        int[] count = new int[10];
        // 每一轮循环按照不同的位数进行排序
        for (int i = 0, r = 1; i < k; ++i, r *= 10) {
            // 将桶清零
            Arrays.fill(count, 0);
            // 统计出现次数
            for (int j = 0; j < n; ++j) {
                int c = (a[j] / r) % 10;
                ++count[c];
            }
            // 计算前缀和
            for (int j = 1; j < 10; ++j) {
                count[j] += count[j - 1];
            }
            // 按顺序将数放到桶中
            for (int j = n - 1; j >= 0; --j) {
                int c = (a[j] / r) % 10;
                bucket[--count[c]] = a[j];
            }
            // 从桶中取回数据
            for (int j = 0; j < n; ++j) {
                a[j] = bucket[j];
            }
        }
    }
    public static void main(String[] args) {
        int[] a = {7, 6, 5, 4, 3, 2, 1, 0};
        radixSort(a);
        for (int i = 0; i < a.length; ++i) {
            System.out.print(a[i] + " ");
        }
        System.out.println();
    }
}
目录
打赏
0
0
0
0
47
分享
相关文章
|
5天前
|
算法系列之数据结构-二叉树
树是一种重要的非线性数据结构,广泛应用于各种算法和应用中。本文介绍了树的基本概念、常见类型(如二叉树、满二叉树、完全二叉树、平衡二叉树、B树等)及其在Java中的实现。通过递归方法实现了二叉树的前序、中序、后序和层次遍历,并展示了具体的代码示例和运行结果。掌握树结构有助于提高编程能力,优化算法设计。
37 9
 算法系列之数据结构-二叉树
|
2天前
|
算法系列之数据结构-Huffman树
Huffman树(哈夫曼树)又称最优二叉树,是一种带权路径长度最短的二叉树,常用于信息传输、数据压缩等方面。它的构造基于字符出现的频率,通过将频率较低的字符组合在一起,最终形成一棵树。在Huffman树中,每个叶节点代表一个字符,而每个字符的编码则是从根节点到叶节点的路径所对应的二进制序列。
22 3
 算法系列之数据结构-Huffman树
|
4天前
|
算法系列之数据结构-二叉搜索树
二叉查找树(Binary Search Tree,简称BST)是一种常用的数据结构,它能够高效地进行查找、插入和删除操作。二叉查找树的特点是,对于树中的每个节点,其左子树中的所有节点都小于该节点,而右子树中的所有节点都大于该节点。
46 22
C 408—《数据结构》算法题基础篇—链表(下)
408考研——《数据结构》算法题基础篇之链表(下)。
89 29
C 408—《数据结构》算法题基础篇—链表(上)
408考研——《数据结构》算法题基础篇之链表(上)。
99 25
C 408—《数据结构》算法题基础篇—数组(通俗易懂)
408考研——《数据结构》算法题基础篇之数组。(408算法题的入门)
73 23
【IO面试题 四】、介绍一下Java的序列化与反序列化
Java的序列化与反序列化允许对象通过实现Serializable接口转换成字节序列并存储或传输,之后可以通过ObjectInputStream和ObjectOutputStream的方法将这些字节序列恢复成对象。
面试官:单核 CPU 支持 Java 多线程吗?为什么?被问懵了!
本文介绍了多线程环境下的几个关键概念,包括时间片、超线程、上下文切换及其影响因素,以及线程调度的两种方式——抢占式调度和协同式调度。文章还讨论了减少上下文切换次数以提高多线程程序效率的方法,如无锁并发编程、使用CAS算法等,并提出了合理的线程数量配置策略,以平衡CPU利用率和线程切换开销。
面试官:单核 CPU 支持 Java 多线程吗?为什么?被问懵了!
大厂面试高频:什么是自旋锁?Java 实现自旋锁的原理?
本文详解自旋锁的概念、优缺点、使用场景及Java实现。关注【mikechen的互联网架构】,10年+BAT架构经验倾囊相授。
大厂面试高频:什么是自旋锁?Java 实现自旋锁的原理?
大厂面试必看!Java基本数据类型和包装类的那些坑
本文介绍了Java中的基本数据类型和包装类,包括整数类型、浮点数类型、字符类型和布尔类型。详细讲解了每种类型的特性和应用场景,并探讨了包装类的引入原因、装箱与拆箱机制以及缓存机制。最后总结了面试中常见的相关考点,帮助读者更好地理解和应对面试中的问题。
113 4

热门文章

最新文章

AI助理

你好,我是AI助理

可以解答问题、推荐解决方案等