内部排序算法5(基数排序)
来源:互联网 发布:seo要学多久 编辑:程序博客网 时间:2024/06/05 05:03
基数排序
多排序码排序的概念
如果每个元素的排序码都是由多个数据项组成的组项,则依据它进行排序时就需要利用多排序码排序。实现多排序码排序有两种常用的方法,最高位优先(Most Significant Digit (MSD) First)和最低位优先(Least Signnificant Digit(LSD) first)。利用多排序码排序实现对单个排序码排序的算法就称为基数排序。
MSD基数排序
思想
在基数排序中,将单排序码
在排序过程中,首先是根据
步骤
- 算法要求事先设置Radix个桶,Radix叫做基数,即排序码的每一位可能取值的数目。为了知道每个桶中会有多少个元素,在算法中还设置了一个辅助数组
count[Radix] ,用count[k] 记忆在处理第i 位时第i 位取值为k 的元素有多少个。k 与基数Radix 有关。如果k 属于十进制整数,Radix 等于10。例如,在上图中当i=1 时,count 各数组元素记忆了不同取值的元素个数,count[0]=1 表示值为0的元素有1个,count[3]=2 表示值为3的元素有2个。 - 在算法中还使用了一个辅助数组
auxArray[] 存放按桶分配的结果,根据count[] 预先算定各桶元素的使用位置。在每一趟向各桶分配结束时,元素都被复制回原表中。
算法实现
#pragma once#include<iostream>#define RADIX 10class MSDRaixSort{public: MSDRaixSort(int length); void create(); void sort(); void print(); ~MSDRaixSort();private: int *elem; int len; void radixSort(int left, int right, int d); int getDigit(int num, int d);};MSDRaixSort::MSDRaixSort(int length) { len = length; elem = new int[len];}inline void MSDRaixSort::create(){ std::cout << "please input the list" << std::endl; for (int i = 0; i < len; i++) { int temp; std::cin >> temp; elem[i] = temp; } std::cout << "finish!" << std::endl;}inline void MSDRaixSort::sort(){ radixSort(0, len - 1, 3);}inline void MSDRaixSort::print(){ for (int i = 0; i < len; i++) { std::cout << elem[i] << " "; } std::cout << std::endl;}MSDRaixSort::~MSDRaixSort(){ delete[] elem;}inline void MSDRaixSort::radixSort(int left, int right, int d) //MSD基数排序算法,从高位到低位对序列进行分配,实现排序{ //其中d时位数,n时待排序元素的个数。left和right时待排序 int i, j, count[RADIX + 1], p1, p2; //元素子序列的始端和尾端,最低位d=1,最高位是d int *auxArray = new int[right - left + 1]; if (d <= 0) { return; } for (j = 0; j < RADIX; j++) { count[j] = 0; } for (i = left; i <= right; i++) //统计各桶元素的个数 { count[getDigit(elem[i], d)]++; } count[RADIX] = right - left + 1; for (j = 1; j < RADIX; j++) //安排各桶元素位置 { count[j] = count[j] + count[j - 1]; } for (i = left; i <= right; ++i) { j = getDigit(elem[i], d); auxArray[count[j] - 1] = elem[i]; --count[j]; } for (i = left, j = 0; i <= right; j++, i++) //从辅助数组auxArray写入原数组。 { elem[i] = auxArray[j]; } for (j = 0; j < RADIX; j++) //将各桶内的元素迭代进行MSD基数排序,直到桶内只有一个元素为止。 { p1 = count[j]; p2 = count[j + 1] - 1; if (p1 < p2) { radixSort(p1, p2, d - 1); } }}inline int MSDRaixSort::getDigit(int num, int d){ int count = 0; while (num > 0) { count++; if (count == d) { return num % 10; } num = num / 10; } return 0;}
//MSD基数排序main文件using namespace std;#include"MSDRadixSorting.h"int main() { MSDRaixSort m(15); m.create(); m.sort(); m.print(); system("pause");}
算法分析
时间复杂度
在算法中调用一个getDigit按位获取用来排序的元素排序码。在上述例子中,从高位到低位一次取待排序元素的各位作为排序码,并设定排序的基数RADIX为10。这就相当于定义了10个接收器,分别接受不同排序码对应的待排序元素。如果待排序元素序列的规模为n,则每个接收器中的待排元素平局为
空间复杂度
在算法中用到了两个数组,一个是
算法的稳定性
MSD基数排序算法是稳定的。
LSD基数排序
思想
LSD基数排序抽取排序码的顺序和MSD基数排序正好相反。使用这种方法,把单排序码
如果对于所有元素的排序码
各个桶都采用链式队列结构,分配到同一桶的排序码用链接指针链接起来。每一个桶设置两个队列指针:一个指向队头(第一个进入此队列的排序码),记为
待排序的
算法的实现
//LSD基数排序算法头文件#pragma once#include<iostream>#define Radix 10struct ElementType{ int data; int link;};class LSDRadixSort{public: LSDRadixSort(int length); void create(); void print(); void sort(int d); //排序核心部分 ~LSDRadixSort();private: int len; ElementType *elem; int getDigit(int num, int d);};LSDRadixSort::LSDRadixSort(int length){ len = length; elem = new ElementType[len + 1]; //由于elem[0]存储了排序的结果,所以分配空间的时候需要多一个}inline void LSDRadixSort::create(){ std::cout << "please input the list: " << std::endl; for (int i = 1; i <= len; i++) { std::cin >> elem[i].data; } std::cout << "finish!" << std::endl;}inline void LSDRadixSort::print() //结果都存储在elem[0]中,按顺序输出就行{ int temp = 0; while (elem[temp].link != 0) { temp = elem[temp].link; std::cout << elem[temp].data << " "; } std::cout << std::endl;}inline void LSDRadixSort::sort(int d) //d表示位数,比如100,则d=3{ int rear[Radix], front[Radix]; int i, j, k, last, current; for (i = 0; i < len; i++) //elem[0]用于存储排序的结果 { elem[i].link = i + 1; } elem[len].link = 0; //循环链表 for (i = 1; i <= d; i++) //从低位向高位排序 { current = elem[0].link; //获得链表中第一个元素 for (j = 0; j < Radix; j++) //初始化front数组 { front[j] = 0; } while (current) { k = getDigit(elem[current].data, i); //获取第i位 if (front[k] == 0) //如果该位没有元素,则放在front位置中。 { front[k] = current; } else //否则,放在链表的尾部 { elem[rear[k]].link = current; } rear[k] = current; //每次放入后改变链表的尾部位置 current = elem[current].link; //移向下一个目标 } j = 0; while (front[j] == 0) //找到第一个值不为0的front { ++j; } elem[0].link = front[j]; //用elem[0]记录排序后的结果 last = rear[j]; //将链表的尾部串向下一个链表的头部,形成完整的链。 for (k = j + 1; k < Radix; ++k) { if (front[k] != 0) { elem[last].link = front[k]; last = rear[k]; } } elem[last].link = 0; //循环链表 }}LSDRadixSort::~LSDRadixSort(){ delete[] elem;}inline int LSDRadixSort::getDigit(int num, int d) //取num的第d位余数{ int count = 1; while (num != 0) { if (count == d) { return num % 10; } num = num / 10; count++; } return 0;}
//LSD基数排序算法main文件using namespace std;#include "LSDRadixSort.h"int main() { LSDRadixSort m(10); m.create(); m.sort(2); m.print(); system("pause");}
结果
算法分析
时间复杂度
在此算法中,对于有n个元素的链表,每趟进行“分配”的while循环需要执行n次,把n个元素分配到Radix个队列中去。进行“收集”的for循环需要执行Radix次,从各个队列中把元素收集起来按顺序链接。若每个排序码有d位,需要重复执行d趟“分配”与“收集”,所以总的时间复杂度为
空间复杂度
在此算法中,使用了两个数组,一个是
算法的稳定性
LSD基数排序是稳定的。
注:本文参考书籍《数据结构精讲与习题详解—考研辅导与答疑解惑》,殷人昆编著,清华大学出版社。
- 内部排序算法5(基数排序)
- 内部排序算法:基数排序
- 八大内部排序算法(中)-基数排序(java实现)
- 内部排序(五)基数排序
- 图解"数据结构--内部排序算法"----分配排序:箱排序、基数排序
- 数据结构中排序算法- 基数排序(5)
- Java内部排序(十)-(基数排序)
- 内部排序之基数排序(RadixSort)
- 内部排序—基数排序
- 排序算法(七)基数排序
- 排序算法-基数排序(RadixSort)
- 基数排序算法(排序详解)
- 排序算法(十一) 基数排序
- 排序算法(4):基数排序
- 排序算法(八):基数排序
- 【数据结构与算法】内部排序之五:计数排序、基数排序和桶排序(含完整源码)
- 【数据结构与算法】内部排序之五:计数排序、基数排序和桶排序(含完整源码)
- 排序(5)基数排序
- 需求工程
- POJ 1789
- HttpURLConnection的简单使用
- 二分快速幂
- go中的main函数和init函数
- 内部排序算法5(基数排序)
- 各大音乐网站接口
- 设计模式03:抽象工厂
- springmvc使用拦截器
- TensorsFlow学习笔记4----面向机器学习专家的深度MNIST教程(Deep MNIST for Experts)
- android 广播的使用
- 【LeetCode】Path Sum III 解题报告
- JDBC
- Python3 random(伪随机数 模块)