zoukankan      html  css  js  c++  java
  • 色々ソート

    十大经典排序算法

    分类

    十大常见排序算法可分为两大类:

    • 比较类排序:通过比较来决定元素间的相对次序,由于其时间复杂度不能突破O(nlogn),因此也称为非线性时间比较类排序。
    • 非比较类排序:不通过比较来决定元素间的相对次序,它可以突破基于比较排序的时间下界,以线性时间运行,因此也称为线性时间非比较类排序。

    img

    复杂度

    img

    • 稳定:如果a原本在b前面,而a=b,排序之后a仍然在b的前面。
    • 不稳定:如果a原本在b的前面,而a=b,排序之后 a 可能会出现在 b 的后面。

    算法详解

    代码原型

    C++

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<vector>
    
    using namespace std;
    
    void inSortName();
    void putIn();
    void putOut();
    
    int num, len;
    vector<int>v; //代排序数组 
    vector<string> sort_name; //算法名字储存数组 
    vector<void(*)()> v_func; //Or:vector<function<void()>> v_func  
    
    ...//十个排序算法函数,具体见后文
    
    void doQuickSort(){ //启动器 
    	len = v.size();
    	quickSort(0, len-1); 
    }
    
    //堆排序
    
    
    int main(){
    	inSortName();
    	putIn();
    	putOut();
    	return 0;
    }
    
    void inSortName(){
    	sort_name.push_back("Bubble Sort");
    	sort_name.push_back("Selection Sort");
    	sort_name.push_back("Insertion Sort");
    	sort_name.push_back("Shell Sort");
    	sort_name.push_back("Merge Sort");
    	sort_name.push_back("Quick Sort");
    	sort_name.push_back("Heap Sort");
    	sort_name.push_back("Counting Sort");
    	sort_name.push_back("Bucket Sort");
    	sort_name.push_back("Radix Sort");
    	v_func.push_back(bubbleSort);
    	v_func.push_back(selectionSort);
    	v_func.push_back(insertionSort);
    	v_func.push_back(shellSort);
    	v_func.push_back(doMergeSort);
    	v_func.push_back(doQuickSort);
    	v_func.push_back(heapSort);
    	v_func.push_back(countingSort);
    	v_func.push_back(bucketSort);
    	v_func.push_back(radixSort);
    }
    
    
    void putIn(){
    	for(int i = 0; i < sort_name.size(); i++){
    		cout << i+1 << "." << sort_name[i] << endl;
    	} 
    	cout << "请输入数字选择排序算法:" << endl;
    	int sort_index;
    	cin >> sort_index;
    	cout << "
    请输入待排序数组以空格隔开, Ctrl+z结束:
    "; 
    	v.clear();
    	while(cin >> num){
    		v.push_back(num);
    	}
    	v_func[sort_index-1](); //有参数在括号中加上即可
    }
    void putOut(){
    	for(int i = 0; i < len-1; i++){
    		cout << v[i] << " ";
    	}
    	cout << v[len-1] << endl;
    }
    

    Java

    import java.lang.reflect.InvocationTargetException;
    import java.lang.reflect.Method;
    import java.util.Scanner;
    import java.util.Vector;
    
    class Sort {
        private static Vector<Integer> v = new Vector<>();
        private static int len, num, testTime = 0;
    
        ...//十大排序算法
    
        public void putIn() {
            Scanner in = new Scanner(System.in);
            v.clear();
            System.out.println("
    请输入待排序数组以空格隔开,Ctrl+D结束:");
            //输入任意数量的整数,Ctrl+D表示Eof
            while (in.hasNext()) {
                num = in.nextInt();
                v.add(num);
            }
        }
    
        public void putOut() {
            for (int i = 0; i < len - 1; i++) {
                System.out.printf("%d ", v.get(i));
            }
            System.out.printf("%d
    ", v.get(len - 1));
        }
    
        public void swap(int x, int y) {
            int temp;
            temp = v.get(x);
            v.set(x, v.get(y));
            v.set(y, temp);
        }
    }
    
    public class Main {
        private static int sortIndex;
        //算法名容器
        private static Vector<String> sortName = new Vector<>();
        //算法函数选择容器
        private static Vector<String> vFunc = new Vector<>();
        private static Scanner in = new Scanner(System.in);
        private static Sort st = new Sort();
    
        public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {
            sortNameList();
            selectSort();
            st.putIn();
            doSort();
            st.putOut();
        }
    
        private static void sortNameList() {
            sortName.add("Bubble Sort");
            sortName.add("Selection Sort");
            sortName.add("Insertion Sort");
            sortName.add("Shell Sort");
            sortName.add("Merge Sort");
            sortName.add("Quick Sort");
            sortName.add("Heap Sort");
            sortName.add("Counting Sort");
            sortName.add("Bucket Sort");
            sortName.add("Radix Sort");
            vFunc.add("bubbleSort");
            vFunc.add("selectionSort");
            vFunc.add("insertionSort");
            vFunc.add("shellSort");
            vFunc.add("doMergeSort");
            vFunc.add("doQuickSort");
            vFunc.add("heapSort");
            vFunc.add("countingSort");
            vFunc.add("bucketSort");
            vFunc.add("radixSort");
        }
    
        private static void selectSort() {
            int i = 0;
            for (String s :
                    sortName) {
                System.out.printf("%d.%s.
    ", ++i, s);
            }
            System.out.printf("请输入数字选择排序算法:
    ");
            sortIndex = in.nextInt() - 1;
        }
    
        private static void doSort() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
            Method method = st.getClass().getMethod(vFunc.get(sortIndex), new Class[0]);
            method.invoke(st, new Object[0]);
        }
    }
    

    冒泡排序(Bubble Sort)

    比较相邻元素,大的向后交换
    

    算法思路

    • 从前往后比较每对相邻元素,将大的元素向后交换。(每次比较完成将得到未排序队列中最大的数排在已排序队列前端)
    • 重复N-1次步骤1,所有元素都完成了从小到大的排序。

    图解

    img

    代码

    C++

    //冒泡排序 
    void bubbleSort(){
    	len = v.size();
    	for(int i = 0; i < len-1; i++){
    		for(int j = 0; j < len-1-i; j++){
    			if(v[j] > v[j+1]){
    				swap(v[j], v[j+1]);
    			}
    		}
    	}
    }
    

    Java

    //冒泡排序
    public void bubbleSort() {
        len = v.size();
        for (int i = 0; i < len - 1; i++) {
            for (int j = 0; j < len - 1 - i; j++) {
                int a = v.get(j), b = v.get(j + 1);
                if (a > b) swap(j, j + 1);
            }
        }
    }
    

    选择排序(Selection Sort)

    不断选择最小(大)元素往前放
    

    因为无论什么数据时间复杂度都是O(n2),表现最稳定的排序算法之一。

    算法思路

    • 从未排序的队列中找到最小(大)元素,存放到排序序列的起始位置;
    • 再从剩余未排序元素中继续寻找最小(大)元素,然后放到已排序序列的末尾;
    • 以此类推,直到所有元素均排序完毕。

    图解

    img

    代码

    C++

    //选择排序 
    void selectionSort(){
    	int min_num;
    	len = v.size();
    	for(int i = 0; i < len-1; i++){
    		min_num = i;
    		for(int j = i+1; j < len; j++){
    			if(v[j] < v[min_num]){
    				min_num = j;
    			}
    		}
    		swap(v[min_num], v[i]);
    	}
    }
    

    Java

    //选择排序
    public void selectionSort() {
        int minNum;
        len = v.size();
        for (int i = 0; i < len - 1; i++) {
            minNum = i;
            for (int j = i + 1; j < len; j++) {
                int a = v.get(minNum), b = v.get(j);
                if (a > b) {
                    minNum = j;
                }
            }
            swap(i, minNum);
        }
    }
    

    插入排序(Insertion Sort)

    将未排序元素插入到排序队列中
    

    算法思路

    • 第一个元素被认为已排序序列;
    • 取出下一个元素,在已排序元素序列中扫描插入合适位置。

    注意

    插入排序通常采用in-place排序(即原位操作,不允许使用临时变量),所以定义两个数组等操作不可取。

    图解

    img

    代码

    C++

    //插入排序
    void insertionSort(){
    	len = v.size();
    	int index, current_num;
    	for (int i = 1; i < len; i++){
    		index = i;
    		current_num = v[i];
    		while(index-1 >= 0 && v[index-1] > current_num){
    			v[index] = v[index-1];
    			index--;
    		}
    		v[index] = current_num;
    	}
    } 
    

    Java

    //插入排序
    public void insertionSort(){
        int index, currentNum;
        len = v.size();
        for (int i = 1; i < len; i++) {
            index = i;
            currentNum = v.get(i);
            while (index-1 >= 0 && v.get(index-1) > currentNum){
                v.set(index, v.get(index-1));
                index--;
            }
            v.set(index, currentNum);
        }
    }
    

    希尔排序(Shell Sort)

    插入排序的改进版。它与插入排序的不同之处在于,它会优先比较距离较远的元素。希尔排序又叫缩小增量排序

    算法思路

    • 设置一个增量,一般 gap = length/2;
    • 将队列按增量进行分组,对每组进行单独的直接插入排序;
    • 缩小增量 gap = gap/2;
    • 重复步骤2,3,直到gap = 1时,排序完成。

    算法讲解

    希尔排序首先设置一个初始增量,我们一般采用gap = length/2为初始增量(此时缩小增量为gap=gap/2),这是希尔建议的增量,被称为希尔增量,这个增量并不是最优的。img

    代码

    C++

    //希尔排序
    void shellSort(){
    	int index, current_num;
    	len = v.size();
    	for (int gap = len/2; gap > 0; gap /= 2){
    		for (int i = gap; i < len; i++){
    			int index = i;
    			current_num = v[i];
    			while(index - gap >= 0 && current_num < v[index-gap]) {
    				v[index] = v[index-gap];
    				index -= gap;
    			}
    			v[index] = current_num;
    		}
    	}
    } 
    

    java

    //希尔排序
    public void shellSort(){
        int index, currentNum;
        len = v.size();
        for (int gap = len/2; gap > 0; gap /= 2) {
            for (int i = gap; i < len; i++) {
                index = i;
                currentNum = v.get(i);
                while (index-gap >= 0 && v.get(index-gap) > currentNum){
                    v.set(index, v.get(index-gap));
                    index -= gap;
                }
                v.set(index, currentNum);
            }
        }
    }
    

    算法分析

    从代码上看,其实就是插入排序上多了一个增量的循环。

    核心在于间隔序列的设定。既可以提前设定好间隔序列,也可以动态的定义间隔序列。

    归并排序(Merge Sort)

    归并排序是建立在归并操作上的一种有效的排序算法。该算法是采用分治法(Divide and Conquer)的一个非常典型的应用。将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。将两个有序表合并成一个有序表,称为2-路归并。

    算法思路

    • 把长度为n的待排序序列分为两个长度n/2的子序列;
    • 对这两个子序列继续采用第一步;
    • 将排序号的子序列进行合并排序为一个排序好的序列;
    • 重复直到得到长度为n的序列。

    注意:当子序列长度为1时,就一定是排序好的序列。

    图解

    img

    代码

    将待排序序列传入mergeSort()。mergeSort会把序列一分为二,然后采用递归思路再次对左右序列进行一分为二,直到每个序列长度为1为止,此时单个序列必定有序。merge()函数会对一分为二的序列进行重新排序组合,能把两个有序序列排列为一个有序序列。
    

    C++

    //归并排序
    vector<int> merge(vector <int> left, vector <int> right){
    	vector <int> result;
    	while(left.size() > 0 && right.size() > 0){
    		if(left[0] <= right[0]){
    			result.push_back(left[0]);
    			left.erase(left.begin());
    		}else{
    			result.push_back(right[0]);
    			right.erase(right.begin());
    		}
    	}
    	while(left.size()){
    		result.push_back(left[0]);
    		left.erase(left.begin());
    	}
    	while(right.size()){
    		result.push_back(right[0]);
    		right.erase(right.begin());
    	}
    	return result;
    } 
    vector<int> mergeSort(vector <int> ary){
    	int len_merge = ary.size();
    	if(len_merge < 2) return ary;
    	int mid = len_merge/2;
    	vector <int> left(ary.begin(), ary.begin()+mid), right(ary.begin()+mid, ary.begin()+len_merge);
    	return merge(mergeSort(left), mergeSort(right));
    } 
    

    Java

    //归并排序
    public Vector<Integer> merge(Vector<Integer> left, Vector<Integer> right) {
        Vector<Integer> result = new Vector<>();
        while (left.size() > 0 && right.size() > 0) {
            if (left.get(0) <= right.get(0)) {
                result.add(left.remove(0));
                ;
            } else {
                result.add(right.remove(0));
            }
        }
        while (left.size() > 0) result.add(left.remove(0));
        while (right.size() > 0) result.add(right.remove(0));
        return result;
    }
    public Vector<Integer> mergeSort(Vector<Integer> ary) {
        /*System.out.printf("%d:%s
    ", testTime++, ary);*/
        int mergeLen = ary.size();
        if (mergeLen < 2) return ary;
        int mid = mergeLen / 2;
        Vector<Integer> left = new Vector<>();
        Vector<Integer> right = new Vector<>();
        int i = 0;
    
        while (i < mid) {
            left.add(ary.get(i++));
        }
        while (i < mergeLen) {
            right.add(ary.get(i++));
        }
        return merge(mergeSort(left), mergeSort(right));
    }
    

    算法分析

    归并排序是一种稳定的排序方法。和选择排序一样,归并排序的性能不受输入数据的影响,但表现比选择排序好的多,因为始终都是O(nlogn)的时间复杂度。代价是需要额外的内存空间

    快速排序(Quick Sort)

    通过一趟排序将待排记录分隔成独立的两部分,其中一部分记录的关键字均比另一部分的关键字小,则可分别对这两部分记录继续进行排序,以达到整个序列有序。

    快速排序思路依旧来源于分治法。

    算法思路

    • 从序列中挑一个元素作为"基准数";
    • 重排序列,将比基准小的元素放在基准数前,大的元素放在基准数后面。
    • 对两边子序列使用递归重复1、2步。

    图解

    img

    代码

    v为待排序序列。对每个进行快排的(子)序列,以最左边的数为基准数,找到一个位置保证左边元素小于基准数,右边元素大于基准数。
    

    C++

    //快速排序 开始left=0 right=len-1
    void quickSort(int left, int right){
    	if(left >= right) return;
    	int i = left, j = right, base = v[left];
    	while(i < j) {
    		while (v[j] >= base && i < j) j--;
    		while (v[i] <= base && i < j) i++;
    		if(i < j){
    			swap(v[i], v[j]);
    		}
    	}
    	v[left] = v[i];
    	v[i] = base;
    	quickSort(left, i-1);
    	quickSort(i+1, right);
    }
    

    Java

    //快速排序
    public void quickSort(int left, int right) {
        if (left >= right) return;
        int i = left, j = right, base = v.get(left);
        while (i < j) {
            while (v.get(j) >= base && i < j) j--;
            while (v.get(i) <= base && i < j) i++;
            if (i < j) swap(i, j);
        }
        v.set(left, v.get(i));
        v.set(i, base);
        quickSort(left, i - 1);
        quickSort(i + 1, right);
    }
    

    堆排序(Heap Sort)

    堆排序(Heapsort)是指利用堆这种数据结构所设计的一种排序算法。堆积是一个近似完全二叉树的结构,并同时满足堆积的性质:即子结点的键值或索引总是小于(或者大于)它的父节点。

    算法思路

    • 将代排序列构成大顶堆(大顶堆构建思路就是对树的所有根节点,从下往上对每个根节点和他的两个或更少的节点进行比较,将其中对大的元素放在根节点位置上)
    • 将堆(树)顶R[1]元素和最后一个R[n]元素进行交换。
    • 对新的无序序列(R[1]...R[n-1])重复上述两步。

    图解

    img

    代码

    C++

    //堆排序
    void adjustHeap(int i){
    	int left = 2*i+1, right = 2*i+2;
    	int max_point = i;
    	if(left < len && v[left] > v[max_point]) max_point = left;
    	if(right < len && v[right] > v[max_point]) max_point = right;
    	if(max_point != i){
    		swap(v[i], v[max_point]);
    		adjustHeap(max_point);
    	}
    }
    void buildMaxHeap(){
    	len = v.size();
    	for(int i = len/2; i >=0; i--) adjustHeap(i);
    }
    void heapSort(){
    	buildMaxHeap();
    	for(int i = v.size()-1; i > 0; i--){
    		swap(v[0], v[i]);
    		len--;
    		adjustHeap(0);
    	}
    	len = v.size();
    }
    

    Java

    //堆排序
    public void adjustHeap(int i) {
        int left = 2 * i + 1, right = 2 * i + 2; //二叉树子节点公式
        int maxPoint = i;
        if (left < len && v.get(left) > v.get(maxPoint)) maxPoint = left;
        if (right < len && v.get(right) > v.get(maxPoint)) maxPoint = right;
        if (maxPoint != i) {
            swap(i, maxPoint);
            adjustHeap(maxPoint);
        }
    }
    public void buildMaxHeap() {
        len = v.size();
        for (int i = len / 2; i >= 0; i--) adjustHeap(i); //二叉树根节点 <= 叶子节点
    }
    public void heapSort() {
        buildMaxHeap();
        for (int i = v.size() - 1; i > 0; i--) {
            swap(0, i);
            len--;
            adjustHeap(0);
        }
        len = v.size();
    }
    

    计数排序(Counting Sort)

    计数排序思想很简单,从待排序序列找出最大和最小的数,在这个范围统计每个数出现的次数。计数排序不再是基于比较的排序,作为一种线性时间复杂度的排序,排序速度快于任何比较排序算法。当k不是很大并且序列比较集中时,计数排序是一个很有效的排序算法。

    计数排序有基础班、优化版、进阶版等,整体思想不变,只是会在节约空间等方面做出更复杂的计算,一下提供进阶版思路。

    算法思路

    • 创建一个新数组Count,大小为待排序序列MaxNum-MinNum+1.创建一个数组(队列)result存储排序后队列。
    • 以待排序序列中数值Value-MinNum为Key,在Count数组中进行计数处理。
    • 对Count数组进行累加求和:count[i] += count[i - 1],此时Count中存储的就是每个数字在result数组中对应的位置(相同数位置下移)
    • 根据Count数组中对应位置对result数组进行赋值。

    图解

    img

    代码

    C++

    //计数排序
    void countingSort() {
    	int max_num = *max_element(v.begin(), v.end()), min_num = *min_element(v.begin(), v.end());
    	len = v.size();
    	vector<int> result(len);
    	int count_size = max_num - min_num + 1;
    	int *count = new int[count_size];
    	memset(count, 0, sizeof(count)*count_size);
    	for (int i = 0; i < len; i++) {
    		count[v[i] - min_num]++;
    	}
    	for (int i = 1; i < count_size; i++) {
    		count[i] += count[i - 1];
    	}
    	for (int i = 0; i < len; i++){
    		result[count[v[i] - min_num] - 1] = v[i];
    		count[v[i] - min_num]--;
    	}
    	v = result;
    }
    

    Java

    //计数排序
    public void countingSort() {
        int maxNum = Collections.max(v), minNum = Collections.min(v);
        len = v.size();
        Vector<Integer> vv = new Vector<Integer>();
        vv.setSize(len);
    
        int countSize = maxNum - minNum + 1;
        int count[] = new int[countSize];
        Arrays.fill(count, 0);
        for (int i = 0; i < len; i++) {
            count[v.get(i) - minNum]++;
        }
        for (int i = 1; i < countSize; i++) {
            count[i] += count[i-1];
        }
        for (int i = 0; i < len; i++) {
            vv.set(count[v.get(i)-minNum] - 1, v.get(i));
            count[v.get(i) - minNum]--;
        }
        v = vv;
    }
    

    算法分析

    计数排序是一个稳定的排序算法。当输入的元素是 n 个 0到 k 之间的整数时,时间复杂度是O(n+k),空间复杂度也是O(n+k),其排序速度快于任何比较排序算法。当是因为消耗空间巨大所以指在K不大且序列较集中时才是个有效的排序算法。

    桶排序(Bucket Sort)

    桶排序是计数排序的升级版。它利用了函数的映射关系,高效与否的关键就在于这个映射函数的确定。桶排序 (Bucket sort)的工作的原理:假设输入数据服从均匀分布,将数据分到有限数量的桶里,每个桶再分别排序(有可能再使用别的排序算法或是以递归方式继续使用桶排序进行排)。

    算法思路

    • 设置一个定量作为桶容量;
    • 根据 ((maxNum - minNum) / bucketSize) + 1 求得所需桶的数量;
    • 遍历数据,把所有数据放入对应桶里;
    • 对每个桶单独排序;
    • 把所有桶数据拼接起来。

    图解

    img

    代码

    C++

    void bucketSort() {
    	int i, j, max_num = *max_element(v.begin(), v.end()), min_num = *min_element(v.begin(), v.end());
    	const int bucket_size = 5; //桶容量
    	int bucket_count = ((max_num - min_num) / bucket_size) + 1; //桶个数
    	vector<int> *buckets = new vector<int>[bucket_count];
    	vector<int> result;
    	for (i = 0; i < v.size(); i++) {
    		buckets[(v[i] - min_num) / bucket_size].push_back(v[i]);
    	}
    	for (i = 0; i < bucket_count; i++) {
    		v = buckets[i];
    		insertionSort();//调用插入排序,代码见插入排序代码。
    		for (j = 0; j < v.size(); j++) {
    			result.push_back(v[j]);
    		}
    	}
    	v = result;
    	len = v.size();
    }
    

    Java

    //桶排序
    public void bucketSort() {
        int i, j, maxNum = Collections.max(v), minNum = Collections.min(v);
        int bucketSize = 5; //桶容量
        int bucketCount = ((maxNum - minNum) / bucketSize) + 1;
        Vector<Integer> result = new Vector<>();
        Vector<Vector<Integer>> buckets = new Vector<Vector<Integer>>();
        for (i = 0; i < bucketCount; i++){
            buckets.add(new Vector<>());
        }
        for (i = 0; i < v.size(); i++) {
            buckets.get((v.get(i) - minNum) / bucketSize).add(v.get(i));
        }
        for (i = 0; i < bucketCount; i++) {
            v = buckets.get(i);
            insertionSort();
            for (j = 0; j < v.size(); j++) {
                result.add(v.get(j));
            }
        }
        v = result;
        len = v.size();
    }
    

    算法分析

    桶排序最好情况下使用线性时间O(n),桶排序的时间复杂度,取决与对各个桶之间数据进行排序的时间复杂度,因为其它部分的时间复杂度都为O(n)。很显然,桶划分的越小,各个桶之间的数据越少,排序所用的时间也会越少。但相应的空间消耗就会增大。

    基数排序(Radix Sort)

    基数排序思路是根据分别根据一个数的每位数(个、十、百...)大小,从低位到高位进行排序,每次排序能保证:如果此位是某几个数的最高位,那么排序结束后队列中这几个数相对位置则是已排序状态。

    算法思路

    • 得到数组中最大数的位数:maxDigit;
    • 循环maxDigit次,从最低位开始对原始数组进行计数排序(因为排序范围只有0~9);

    图解

    img

    代码

    C++

    //基数排序
    void radixSort() {
    	int mod = 10, dev = 1, bit_num, max_digit;
    	int i, j, k;
    	vector <int>* buckets;
    	max_digit = log10(*max_element(v.begin(), v.end())) + 1; //求容器中最大数的位数
    	for (i = 0; i < max_digit; i++, dev *= 10, mod *= 10) {
    		buckets = new vector<int>[10];
    		for (j = 0; j < v.size(); j++) {
    			bit_num = v[j] % mod / dev;
    			buckets[bit_num].push_back(v[j]);
    		}
    		v.clear();
    		for (j = 0; j < 10; j++) {
    			for (k = 0; k < buckets[j].size(); k++) {
    				v.push_back(buckets[j][k]);
    			}
    		}
    	}
    	len = v.size();
    }
    

    Java

    //基数排序
    public void radixSort() {
    int mod = 10, dev = 1,bitNum, maxDigit;
    int i, j;
    Vector<Vector<Integer>> buckets;
    maxDigit = String.valueOf(Collections.max(v)).length(); //获取数组v最最大数的位数
    for (i = 0; i < maxDigit; i++, dev *= 10, mod *= 10) {
        buckets = new Vector<Vector<Integer>>();
        buckets.setSize(10);
        for (j = 0; j < v.size(); j++) {
            bitNum = v.get(j) % mod / dev;
            if (buckets.get(bitNum) == null) {
                buckets.set(bitNum, new Vector<>());
            }
            buckets.get(bitNum).add(v.get(j));
        }
        v.clear();
        for (j = 0; j < buckets.size(); j++) {
            if (buckets.get(j) != null) {
                while (buckets.get(j).size() != 0){
                    v.add(buckets.get(j).firstElement());
                    buckets.get(j).remove(0);
                }
            }
        }
    }
    len = v.size();
    }
    

    算法分析

    基数排序基于分别排序,分别收集,所以是稳定的。但基数排序的性能比桶排序要略差,每位数的桶分配都需要O(n)的时间复杂度,而分配之后得到的新序列又需要O(n)的时间复杂度。假如待排数据的最大数的位数(max_digit)为d,则基数排序的时间复杂度将是O(d*2n) ,当然d要远远小于n,因此基本上还是线性级别的。

    基数排序的空间复杂度为O(n+k),其中k为桶的数量。一般来说n>>k,因此额外空间需要大概n个左右。

    源代码下载

    链接:https://pan.baidu.com/s/1hUbSsRV8rZUEYleyHF0UFQ
    提取码:Yuri

  • 相关阅读:
    HashMap 常问的 9 个问题
    P1855 榨取kkksc03
    Codeforces Round #697 (Div. 3) A. Odd Divisor
    P1474 [USACO2.3]Money System / [USACO07OCT]Cow Cash G
    Codeforces Round #704 (Div. 2) D. Genius's Gambit
    P2800 又上锁妖塔
    P2066 机器分配
    P3399 丝绸之路
    P1351 [NOIP2014 提高组] 联合权值
    P4290 [HAOI2008]玩具取名
  • 原文地址:https://www.cnblogs.com/AkimotoAkira/p/14023436.html
Copyright © 2011-2022 走看看