循环队列的实现及应用——桶排序bucket_sort、基数排序radix_sort

一、循环队列的实现

代码解释

1、完成初始化

2、定义方法

3、测试实例

4、完整代码

javascript 复制代码
class AQueue:
    def __init__(self, size=10):
        self.__mSize = size
        self.__front=0
        self.__rear = 0
        self.__listArray = [None] * size

    #清空元素
    def clear(self):
        self.__front = 0
        self.__rear = 0
        for i in range(self.__mSize):
            self.__listArray[i]=None
    # 入队操作
    def enqueue(self, item):
        if not self.is_full():
            self.__rear=(self.__rear+1)%self.__mSize
            self.__listArray[self.__rear]=item
        elif self.is_full():
            raise ValueError("Queue is Full.")
    # 出队操作
    def dequeue(self):
        if not self.is_empty():
            self.__front=(self.__front+1)%self.__mSize
            self.item=self.__listArray[self.__front]
            self.__listArray[self.__front]=None
            return self.item
        elif self.is_empty():
            raise ValueError("Queue is empty.")
    # 判空,检查队列是否为空
    def is_empty(self):
        return self.__front==self.__rear
    # 判满,注意并不是所有的位置都有元素才是满,当只有一个是None时就满了,有点像链表的哑结点
    def is_full(self):
        return ((self.__rear+1)%self.__mSize==self.__front)

    def __repr__(self):  # 显示队列中所有元素,数组切片左闭右开
        return str(self.__listArray[:self.__mSize])

if __name__=='__main__':
    queue=AQueue(5)
    queue.enqueue(1)
    print(queue)
    print(queue.dequeue())
    queue.enqueue(2)
    queue.enqueue(3)
    queue.enqueue(4)
    print(queue)
    print(queue.dequeue())
    queue.enqueue(5)
    print(queue)
    queue.enqueue(6)
    print(queue.is_full())
    print(queue)
    queue.dequeue()
    print(queue)

二、队列的应用------桶排序bucket_sort

对于排序法,我们已经学了三种简单排序:直接插入排序、冒泡排序、选择排序,快速排序、归并排序。那为什么还要学习桶排序呢?

因为前面提到的几种排序方法全是基于比较的排序,时间复杂度在最好的情况下才是O(nlogn)

而桶排序没有用比较就将数字排好序了,虽然以消耗空间为代价,但是时间复杂度得到了很大的提升

1、图示

2、代码

javascript 复制代码
#s代表待排序数组,m代表最大元素值,n代表元素个数
from AQueue import *
def bucket_sort(s,m,n):
    #创建m+1个桶
    b = [AQueue() for _ in range(0, m + 1)]
    #把对应的数字放进去
    for i in range(0,n):
        b[s[i]].enqueue(s[i])
    for j in range(0, m + 1):#检查桶
        print(b[j])
    i=0
    for j in range(0,m+1):#依次遍历桶并出队到s中
        while b[j].is_empty()==False:
            s[i]=b[j].dequeue()
            i+=1
    print(s)

s=[3,1,2,5,1,2,3]
bucket_sort(s,5,7)

3、时间复杂度分析

当m<n时,桶排序的时间复杂度会降到O(n)

但是当待排序数是[2,3,4,6666]

那么m=6666,要创建6667个队列显然造成了空间的极度浪费

并且O(m)也不一定会比O(nlogn)好到哪里去

因此接下来我们引入桶排序的升级版------基数排序

二、桶排序升级版------基数排序radix_sort

(一)对数字进行排序

1、图示

假设还用桶排序,上面这个例子要创建673个桶

而基数排序分别把位数看作一趟分配回收

最多有几位就进行几趟分配回收

2、代码

注意代码中print()的地方,将有助理解代码运行效果,输出样例已给出

(1)代码总览
(2)测试样例
(3)完整代码
javascript 复制代码
from AQueue import *
def radix_sort_nums(s):
    # 计算扫描趟数:最长字符串长度
    circulation=len(str(max(s)))
    # 开始扫描,从个位开始 i=0是个位
    for i in range(circulation):
        # 计算桶的边界
        unit_ten_hundred_values = []#存放个位十位等的值
        count = [0] * 10
        for j in s:
            unit_ten_hundred_value = (j // (10 ** i)) % 10  # 个位数:j//0
            count[unit_ten_hundred_value] += 1#个位数是几,对应的下标的桶里就应该多一个位置
            unit_ten_hundred_values.append(unit_ten_hundred_value)#把这个数的个位数放进去
        print(unit_ten_hundred_values)
        print(count)
        # 创建10个桶,每个桶有边界(由于有一个位置是相当于哑结点的作用,所以要加一)
        b = []
        for k in count:
            b.append(AQueue(k + 1))
        print(b)
        # 把对应的数字放进去
        for i in range(len(s)):#个位数值放到对应的桶中,但是入队的是s里的值,而非个位数值
            b[unit_ten_hundred_values[i]].enqueue(s[i])
        for j in range(10):  # 检查桶
            print(b[j])
        i = 0
        for j in range(10):  # 依次遍历桶并出队到s中
            while b[j].is_empty() == False:
                s[i] = b[j].dequeue()
                i += 1
        print(s)
    print(s)

s=[200,321,453,673,72,63]
radix_sort_nums(s)

(二)对字符串进行排序

和对数组的排序一样,对字母的排序实质上是对其ASCII码的排序

1、代码总览

2、完整代码:

javascript 复制代码
from AQueue import *
# 针对字符串的基数排序
def radix_sort_str(arr):
    # 计算最长字符串的长度
    max_len = max(len(s) for s in arr)

    # 进行max_len次排序,每次按一个字符排序
    for i in range(max_len - 1, -1, -1):  # 从最高位到最低位排序
        # 创建58个桶(ASCII字符集大小)大写A65~小写z122
        buckets = [AQueue(1000) for _ in range(58)]
        # 将字符串分配到对应的桶中
        for s in arr:
            # 分配桶
            buckets[ord(s[i])-65].enqueue(s)
        # 回收所有桶中的字符串,并放回arr中
        i = 0
        for j in range(58):  # 依次遍历桶并出队到s中
            while buckets[j].is_empty() == False:
                arr[i] = buckets[j].dequeue()
                i += 1
    return arr

# 示例字符串数组
arr = ["ErAfCDdQ", "LVVzAQtE", "mhcyRgzp", "aOwDbbJa", "WfHWOdtb", "gOLsdkrf"]
# 对字符串数组进行基数排序
sorted_arr = radix_sort_str(arr)
# 打印排序后的结果
print(sorted_arr)
#验证
print(sorted(arr))

三、综合

当要求排序的数和字符串量很大并存储在文件中时,实现代码如下

javascript 复制代码
from AQueue import *
def radix_sort_nums(s):
    #计算扫描趟数:最长数字长度
    circulation=len(str(max(s)))
    # 开始扫描,从个位开始 i=0是个位
    for i in range(circulation):
        # 计算桶的边界
        unit_ten_hundred_values=[]#存放个位十位等的值
        count = [0] * 10
        for j in s:
            unit_ten_hundred_value = (j // (10 ** i)) % 10  # 个位数:j//0
            count[unit_ten_hundred_value] += 1
            unit_ten_hundred_values.append(unit_ten_hundred_value)

        #创建10个桶,每个桶有边界
        b=[]
        for k in count:
            b.append(AQueue(k+1))
        # 把对应的数字放进去
        for i in range(len(s)):
            b[unit_ten_hundred_values[i]].enqueue(s[i])
        i = 0
        for j in range(10):  # 依次遍历桶并出队到s中
            while b[j].is_empty() == False:
                s[i] = b[j].dequeue()
                i += 1
    print(s)

def radix_sort_str(arr):
    # 计算最长字符串的长度
    max_len = max(len(s) for s in arr)

    # 进行max_len次排序,每次按一个字符排序
    for i in range(max_len - 1, -1, -1):  # 从最高位到最低位排序
        # 创建58个桶(ASCII字符集大小)大写A65~小写z122
        buckets = [AQueue(1000) for _ in range(58)]
        # 将字符串分配到对应的桶中
        for s in arr:
            # 分配桶
            buckets[ord(s[i])-65].enqueue(s)
        # 回收所有桶中的字符串,并放回arr中
        i = 0
        for j in range(58):  # 依次遍历桶并出队到s中
            while buckets[j].is_empty() == False:
                arr[i] = buckets[j].dequeue()
                i += 1
    return arr

def read_file_nums(filename):
    f=open(filename,'r')
    datas=f.read()
    f.close()
    s=datas.split()
    s=[int(item) for item in s]
    return s

def read_file_str(filename):
    f=open(filename,'r')
    datas=f.read()
    f.close()
    s=datas.split()
    return s

def main():
    # 整数类型数据排序
    s = read_file_nums('radix1.txt')
    radix_sort_nums(s)
    print("Sorted integer data:")
    print(s)

    # # 字符串类型数据排序
    str_data = read_file_str('radix2.txt')
    sorted_str_data = radix_sort_str(str_data)
    print("\nSorted string data:")
    print(sorted_str_data)

if __name__ == "__main__":
    main()

radix1.txt

radix2.txt

相关推荐
林开落L8 分钟前
前缀和算法习题篇(上)
c++·算法·leetcode
远望清一色9 分钟前
基于MATLAB边缘检测博文
开发语言·算法·matlab
tyler_download11 分钟前
手撸 chatgpt 大模型:简述 LLM 的架构,算法和训练流程
算法·chatgpt
封步宇AIGC17 分钟前
量化交易系统开发-实时行情自动化交易-3.4.1.2.A股交易数据
人工智能·python·机器学习·数据挖掘
何曾参静谧17 分钟前
「Py」Python基础篇 之 Python都可以做哪些自动化?
开发语言·python·自动化
Prejudices21 分钟前
C++如何调用Python脚本
开发语言·c++·python
SoraLuna31 分钟前
「Mac玩转仓颉内测版7」入门篇7 - Cangjie控制结构(下)
算法·macos·动态规划·cangjie
我狠狠地刷刷刷刷刷34 分钟前
中文分词模拟器
开发语言·python·算法
鸽鸽程序猿35 分钟前
【算法】【优选算法】前缀和(上)
java·算法·前缀和
wyh要好好学习37 分钟前
C# WPF 记录DataGrid的表头顺序,下次打开界面时应用到表格中
开发语言·c#·wpf