• 浅显易懂的桶排序


    想准备将所有的排序算法都总结出来,方便你查阅,也方便我复习和记忆,下面来说桶排序:

    首先必须申明,桶排序和计数排序完全不同,不可混为一谈:(这里实例用单链表来操作)

    还是老方法,看文字就是烦,直接上图,图文结合,永远都是王道:

    1.假设:桶待排序列:{ 49, 38, 35, 97, 76, 73, 27, 49 ,34,78}

    看了之后有没有特莫感觉就是哈希桶,哈哈,满足一定条件差不多就是啦;言归正传,key值就是待排序序列,Bucket为桶,数据按某种函数,映射到桶中

    2.关于映射及桶排原理分析:

      桶中数据的十位都一样,那么映射函数算出的桶号就是这些数据的十位,也就是说,这种映射函数,目的就是为了找出数据的共同特点,可能是求余(哈希表直接定址,就是这样),可能是除某数求商,本例中就是取商;

    即就是所有数据除某数取得的商相同的都放一个桶中,如图中的3号桶,刚开始,3号桶中的数据是无序的,第一遍操作,只能保证这些数据一定是在这个桶中,

    但是桶中的顺序还是要排的,之后,遍历一遍桶,输出即就是一个有序序列,就这几句话,我感觉说完了,至于更深层 的剖析,稍后再说,先来代码:

    #pragma once
    
    //每一个节点的结构
    struct node
    {
    	int key;  //关键字,在桶中统计桶中数据量,在数据节点中就是节点的数据
    	struct node *next;
    };
    
    //声明:
    void PrintBucketSort(node** bucket, int bucket_size);
    int f(int x);
    
    void BucketSort(int* a, int size,int bucket_size)
    {
    	assert(a);
    	
    	//给桶申请空间
    	node** bucket = new node*[bucket_size*sizeof(node)]; 
    
    	//初始化
    	for (int i = 0; i < bucket_size; ++i)
    	{
    		bucket[i] = new node[sizeof(node)]; //每一个桶
    		bucket[i]->key = 0;
    		bucket[i]->next = nullptr;
    	}
    
    	for (int j = 0; j < size; ++j)
    	{
    		node* sub_node = new node[sizeof(node)]; //桶下的每一个节点
    		sub_node->key = a[j];
    		sub_node->next = nullptr;
    
    		//计算这数据在哪个桶中
    		int num = f(a[j]);
    
    		//让一个指针指向这个桶号的头
    		node* sub_head = bucket[num];
    
    		//开始插入
    		if (sub_head->next == nullptr)
    		{
    			bucket[num]->next = sub_node;
    			bucket[num]->key++;
    		}
    		//该桶号不为空,那么插入排序
    		else
    		{
    			while (sub_head->next != nullptr && sub_node->key >= sub_head->next->key)
    			{
    				sub_head = sub_head->next;
    			}
    
    			sub_node->next = sub_head->next;
    			sub_head->next = sub_node;
    			bucket[num]->key++;
    		}
    	}
    	//打印
    	PrintBucketSort(bucket, bucket_size);
    }
    
    //映射函数
    int f(int x)
    {
    	return (x / 10);
    }
    
    //打印
    void PrintBucketSort(node** bucket, int bucket_size)
    {
    	//多少桶链(桶号)
    	for (int i = 0; i < bucket_size; ++i)
    	{
    		node* cur = bucket[i]->next;
    		while (cur)
    		{
    			cout << cur->key << " ";
    			cur = cur->next;
    		}
    	}
    	cout << endl;
    }
    
    void Test7()
    {
    	int a[10] = { 49, 38, 35, 97, 76, 73, 27, 49, 34, 78 };
    	cout << "桶排序" << endl;
    	BucketSort(a, 10, 10);  //桶数据最大才97,所以需要10个桶
    }
    哎呀,敲了我十几分钟,看看结果:

    第一个就是排序,第二个就是数据在桶中的分布,横行代表桶,10个桶,没有数据的桶是0;

    桶排序就是这样:

    对于N个待排数据,M个桶,平均每个桶[N/M]个数据的桶排序平均时间复杂度为:


                 O(N)+O(M*(N/M)*log(N/M))=O(N+N*(logN-logM))=O(N+N*logN-N*logM)


    当N=M时,即极限情况下每个桶只有一个数据时。桶排序的最好效率能够达到O(N)
     
    桶排序的平均时间复杂度为线性的O(N+C),其中C=N*(logN-logM)。如果相对于同样的N,桶数量M越大,其效率越高,最好的时间复杂度达到O(N)。 

    当然桶排序的空间复杂度 为O(N+M),如果输入数据非常庞大,而桶的数量也非常多,则空间代价无疑是昂贵的。

    此外,桶排序是稳定的。

    赐教!

  • 相关阅读:
    接口和抽象类的异同点
    实体对象间传值克隆
    什么是反射&反射的8个类的用法
    ERP中反射的两个实例
    基础02 Java 跨平台原理
    基础01 dos命令
    lists删除
    多字段 java对象排序
    Java对象排序
    MySQL表中数据的迁移
  • 原文地址:https://www.cnblogs.com/melons/p/5791842.html
Copyright © 2020-2023  润新知