##时间复杂度O(n)
目录
##桶排序
##原理
桶排序的核心思想就是,将一组无序数字,通过一定的方式散列到不同的桶中,且桶之间有大小顺序(例:后面一个桶中的最小数字都比前面桶中的最大数字大),对每个桶进行排序(选择排序等)然后将每个桶中的元素依次取出,即可实现桶排序
考虑一个长度为 𝑛 的数组,其元素是范围 [0,1) 内的浮点数。
- 初始化 𝑘 个桶,将 𝑛 个元素分配到 𝑘 个桶中。
- 对每个桶分别执行排序(这里采用编程语言的内置排序函数)。
- 按照桶从小到大的顺序合并结果。
##图例
##代码实现
//python代码示例 ##桶排序 def bucket_sort(a): """桶排序""" #初始化k = n / 2 个桶,预期向每个桶中分配2个元素 k = len(a) // 2 buckets = [[] for _ in range(k)] #将元素分配到各个列表桶中 for num in a : #输入数据的范围为[0,1),使用num * k 映射到索引范围[0,k-1] i = int(num * k) buckets[i].append(num) print(buckets) for bucket in buckets : bucket.sort() print(buckets) i = 0 for bucket in buckets : for num in bucket : a[i] = num i += 1 return a a = [0.49,0.96,0.82,0.09,0.57,0.43,0.91,0.75,0.15,0.37] print(bucket_sort(a))
//c++代码示例 void bucketSort(vector<float> &a) { int k = a.size() / 2 ; vector<vector<float>> buckets(k) ; for (float num : a) { int i = num * k ; buckets[i].push_back(num) ; } for (vector<float> &bucket: buckets) { sort(bucket.begin(),bucket.end()) ; } int i = 0 ; for (vector<float> &bucket : buckets) { for (float num : bucket) { a[i++] = num ; } } }
//python代码示例 def Selection_Sort(a) : n = len(a) for i in range(0,n) : min = i for j in range(i+1,n) : if a[j] < a[min] : min = j a[min] , a[i] = a[i] ,a[min] #选取足够大的桶数M,如果数据分布还足够均匀,复杂度可以逼近O(n) def Bucket_sort(a) : a_min = min(a) a_max = max(a) bucketCount = 3 bucket = [[], [], []] #关键点 perBucket = (a_max - a_min + bucketCount) // bucketCount #计算出来每个桶的区间范围 for num in a : buckerIndex = (num - a_min) // perBucket bucket[buckerIndex].append(num) for i in range(bucketCount) : Selection_Sort(bucket[i]) idx = 0 for i in range(bucketCount) : for num in bucket[i] : a[idx] = num idx += 1
##计数排序
##原理
最简单的实现方式:(不考虑数据为数据对象)
给定一个长度为 𝑛 的数组
nums
,其中的元素都是“非负整数”,
- 遍历数组,找出其中的最大数字,记为 𝑚 ,然后创建一个长度为 𝑚+1 的辅助数组
counter
。- 借助
counter
统计nums
中各数字的出现次数,其中counter[num]
对应数字num
的出现次数。统计方法很简单,只需遍历nums
(设当前数字为num
),每轮将counter[num]
增加 1 即可。- 由于
counter
的各个索引天然有序,因此相当于所有数字已经排序好了。接下来,我们遍历counter
,根据各数字出现次数从小到大的顺序填入nums
即可。
##图例
##代码实现
//python代码示例 #计数排序-借用了哈希思想 def CountingSort(a) : n = len(a) cntLen = max(a) + 1 cnt = [0] * cntLen for val in a : cnt[val] += 1 print(cnt) n = 0 for val in range(cntLen) : while cnt[val] > 0 : cnt[val] -= 1 a[n] = val n += 1 a = [2,3,1,3,2,1,4,2,4,6,2] CountingSort(a) print(a)
//c++代码示例 void conutSortNaive(vector<int> &a) { int m = 0 ; for (int num : a) { m = max(m,num) ; } vector<int> counter(m+1,0) ; for (int num : a) { couuter[num]++ ; } int i = 0 ; for (int num = 0 ; num < m + 1 ; num++) { for (int j = 0 ; j < counter[num] ; j++,i++) { a[i] = num ; } } }
##计数排序进阶版本
##原理
(若输入数据为对象时,最简单的基数排序就失效了)
假设输入数据是商品对象,我们想按照商品价格(类的成员变量)对商品进行排序,而上述算法只能给出价格的排序结果。
##图例
##代码实现
#python代码示例 def counting_sort(a) : """计数排序""" #可排序对象,并且是稳定排序 #1.统计数组最大元素m m = max(a) #2.统计各数字出现的次数 #counter[num]代表num出现的次数 counter = [0] * (m + 1) for num in a : counter[num] += 1 print(counter) #3.求counter的前缀和,将出现次数转化成尾索引 #即counter[num] - 1 是num在res中最后一次出现的索引 for i in range(m) : counter[i + 1] += counter[i] #倒叙遍历a,将各个元素填入到结果数组res print(counter) n = len(a) res = [0] * n for i in range(n-1,-1,-1) : num = a[i] res[counter[num] - 1] = num counter[num] -= 1 print(res) for i in range(n) : a[i] = res[i] a = [2,3,1,3,2,1,4,2,4,6,2] counting_sort(a) print(a)
//c++代码示例 void countingSort(vector<int> &a) { int m = 0 ; for (int num : a) { m = max(m,num) ; } vector<int> counter(m+1,0) ; for (int num : a) { counter[num]++ ; } for (int i = 0 ; i < m ; i++) { counter[i+1] += counter[i] ; } int n = a.size() ; vector<int> res(n,0) ; for (int i = n-1 ; i >= 0 ; i--) { int num = a[i] ; res[counter[num] - 1] num ; counter[num] -= 1 ; } // for (int i = 0 ; i < n ; i++) // { // a[i] = res[i] ; // } a = res ; }
##基数排序
##原理
通过迭代,利用数位来实现排序,具体的实现分为以下及部分:
1.定义是个数位桶0-9分别用来存储每一次迭代的结果
2.利用base来实现数位的移动(base*=10)
3.利用整除和取模操作来得到具体的数位【num // base % 10】
4.迭代
##图例
##代码实现
#python代码示例 def RadixSort(a) : base = 1 maxv = max(a) while base <= maxv : bucket = [] for _ in range(10) : bucket.append([]) for num in a : idx = num // base % 10 bucket[idx].append(num) l = 0 for idx in range(10) : for v in bucket[idx] : a[l] = v l+=1 print(a) base = base * 10
#python代码示例 def digit(num,exp) : """获取元素 num 的第 k 位,其中 exp = 10^(k-1)""" # 传入 exp 而非 k 可以避免在此重复执行昂贵的次方计算 return (num // exp) %10 def counting_sort_digit(a,exp) : """计数排序(根据 nums 第 k 位排序)""" # 十进制的位范围为 0~9 ,因此需要长度为 10 的桶数组 counter = [0] *10 n = len(a) for i in range(n) : d = digit(a[i],exp) counter[d] += 1 # 求前缀和,将“出现个数”转换为“数组索引” for i in range(1,10) : counter[i] += counter[i-1] res = [0] * n for i in range(n-1,-1,-1) : d = digit(a[i],exp) j = counter[d] - 1 res[j] = a[i] counter[d] -= 1 for i in range(n) : a[i] = res[i] def radix_sort(a) : m = max(a) exp = 1 while exp <= m : counting_sort_digit(a,exp) exp = exp * 10
//c++代码示例 int digit(int num , int exp) { return (num / exp) % 10 ; } void countingSortDigit(vector<int> &nums ,int exp) { vector<int> counter(10,0) ; int n = nums.size() ; for (int i = 0 ; i < n ; i++) { int d = digit(nums[i],exp) ; counter[d]++ ; } for (int i = 1 ; i < 10 ; i++) { counter[i] += counter[i-1] ; } vector<int> res)(n,0) ; for (int i = n-1 ; i >= 0 ; i--) { int d = digit(nums[i],exp) ; int j = counter[d] - 1 ; res[j] = nums[i] ; counter[d]-- ; } for (int i = 0 ; i < n ; i++) { nums[i] = res[i] ; } } void radixSort(vector<int> &nums) { int m = *max_element(nums.begin(),nums.end()) ; for (int exp = 1 ; exp <= m ; exp *= 10) { countingSortDigit(nums,exp) ; } }