基数排序

基数排序和其他排序方法不同,实现基数排序不需要对元素之间进行比较,它主要是利用多个关键字进行排序。

1.桶排序

例如,年纪有1000个人,他们的学习成绩在0-100分之间,那么,对这1000个人排序我们只需要按照分数0,1,2,… ,99,100,建立101个桶,然后依次把每个学生的成绩放入桶内,这样就完成了排序。
算法分析:

  1. 首先我们知道学生的成绩范围,ScanForMax(SqList L),才知道我要建立多少个桶;
  2. 要依次读入每个学生的成绩,然后按照成绩放入桶内。
  3. 最后按照桶的顺序依次把所有成绩输出
void Budget_Sort(SqList *L)
{/*桶排序,每个关键字对应一个桶*/
	
	int NumBudget;
	typedef struct Node
	{/*定义一个链表*/
		ElementType data;
		struct Node *next;
	}List;

	typedef struct
	{/*桶*/
		List *Li;//存桶中元素链表
		int NumElement;//桶中元素的个数
	}Budget;

	/*首先应该知道序列的最大值是多少,才能确定分配多少个桶,每个数据放入一个桶,每个桶可能放多个相同的数据*/
	NumBudget = ScanForMax(*L);
	Budget *Budg;
	Budg = (Budget*)malloc(sizeof(Budget)*(NumBudget+1));
	if (!Budg)//分配失败
		exit(-1);
	for (int i = 0; i <= NumBudget; i++)
	{/*初始化每个桶*/
		Budg[i].NumElement = 0;
		Budg[i].Li = NULL;
	}
	int i = 0;
	while (i<L->Length)
	{/*依次读入每个元素,插入到相应的桶的链表第一个位置*/
		List *p;
		p= (List*)malloc(sizeof(List));//为链表申请一个节点空间
		if (!p)
			exit(-1);
		p->data = L->data[i];
		p->next = Budg[L->data[i]].Li;
		Budg[L->data[i]].Li = p;//桶的链表头变成p
		Budg[L->data[i]].NumElement++;//桶中的元素数量加1
		i++;
	}
	int j=0;
	List *p;
	for (int i = 0; i <=NumBudget; i++)
	{/*将桶中的数据取出来按顺序放入原顺序表*/
		p = Budg[i].Li;//链表头指针
		while (p)
		{
			L->data[j++] = p->data;
			p = p->next;
		}
	}
}

性能分析:算法复杂度为O(M+N),M为桶的个数,N为待排序元素个数。当N>>M时这种方法效率很高,但是当M>>N时,例如10个学生有成绩分布在0~1000分,这种方法就效率低下。

2. 基数排序(次位优先)

如果待排序元素是10进制数,那么我们就建立10个桶(0,1,2,… ,8,9);同理八进制就8八个桶。然后我们需要知道元素的最大值是多少位的,这样就排多少次顺序。例如如果有百位,我们就先按照个位pass一次,把元素根据个位值放在各个桶内,结在一次将元素从个位桶里取出来再根据十位进行排序,最后将元素从十位桶里取出来放入百位桶里,这样得到的元素就是排好序的序列。

void radix_Sort(SqList *L)
{/*基数排序,次数优先,如果是十进制数,那么就建立10个桶*/
	typedef struct//定义桶
	{
		ElementType data[BudgetSize];
		int NumElement;//桶中元素个数
	}Budget;

	typedef struct 
	{
		Budget Budg[10];
	} Pass;

	Pass pass_single;//个位,十个桶每个桶里存放个位数为i的数据
	Pass pass_decade;//十位
	Pass pass_hundred;//百位
	Budget pass[10];
	for (int i = 0; i < BudgetSize; i++)//初始化
	{
		pass_single.Budg[i].NumElement = 0;
		pass_decade.Budg[i].NumElement = 0;
		pass_hundred.Budg[i].NumElement = 0;
	}

	int m;
	for (int i = 0; i < L->Length; i++) //按个位入桶
	{
		int single = L->data[i] % 10;//求出各个位数
		m = pass_single.Budg[single].NumElement;//当前桶内元素个数
		pass_single.Budg[single].data[m] = L->data[i];
		pass_single.Budg[single].NumElement++;
	}

	int n;
	for (int i = 0; i < 10; i++)//把数从个位pass的各桶中取出来,放入pass_decade的桶
	{
		for (int j = 0; j < pass_single.Budg[i].NumElement; j++)
		{
			int decade = (pass_single.Budg[i].data[j]/10 )%10;//求十位数
			n=pass_decade.Budg[decade].NumElement;
			pass_decade.Budg[decade].data[n] = pass_single.Budg[i].data[j];
			pass_decade.Budg[decade].NumElement++;
		}
	}
	int k1;
	for (int i = 0; i < 10; i++)//把数从十位pass的各桶中取出来,放入百位桶
	{
		for (int j = 0; j < pass_decade.Budg[i].NumElement; j++)
		{
			int hundred = pass_decade.Budg[i].data[j] / 100;//求百位数
			k1 = pass_hundred.Budg[hundred].NumElement;
			pass_hundred.Budg[hundred].data[k1] = pass_decade.Budg[i].data[j];
			pass_hundred.Budg[hundred].NumElement++;

		}
	}
	
	int k2 =0;
	for (int t = 0; t < 10; t++)//把数从百位pass的各桶中取出来,放入顺序表List
	{
		for (int j = 0; j < pass_hundred.Budg[t].NumElement; j++)
		{
			L->data[k2++] = pass_hundred.Budg[t].data[j];
		}
	}
}

性能分析:这种方法是对简单的桶排序的一种改进。有效解决了M>>N的效率低问题。其算法复杂度为O(p(N+B)),P为pass的次数,N为待排序元素个数,B为桶的数目。额外的空间复杂度:O(N+B),B个桶加上把元素存在桶内

完整的测试代码

#include "pch.h"
#include <iostream>
#include<stdio.h>
#include<stdlib.h>
#define MaxSize 100
#define BudgetSize 10

typedef int ElementType;
typedef struct
{
	ElementType data[MaxSize];
	int Length;
}SqList;

void Swap(ElementType *a, ElementType *b)
{
	ElementType tmp;
	tmp = *a;
	*a = *b;
	*b = tmp;
}

void DisplaySqList(SqList L)
/*打印序列*/
{
	int i;
	for (i = 0; i < L.Length; i++)
	{
		printf("%-4d", L.data[i]);
	}
	printf("\n");
}


ElementType ScanForMax(SqList L)
{
	int pos = 0;
	ElementType Temp;
	for (int i = 0; i < L.Length; i++)
	{
		Temp = L.data[pos];
		if (Temp < L.data[i])
			pos = i;
	}
	return L.data[pos];
}

void Budget_Sort(SqList *L)
{/*桶排序,每个关键字对应一个桶*/
	
	int NumBudget;
	typedef struct Node
	{/*定义一个链表*/
		ElementType data;
		struct Node *next;
	}List;

	typedef struct
	{/*桶*/
		List *Li;//存桶中元素链表
		int NumElement;//桶中元素的个数
	}Budget;

	/*首先应该知道序列的最大值是多少,才能确定分配多少个桶,每个数据放入一个桶,每个桶可能放多个相同的数据*/
	NumBudget = ScanForMax(*L);
	Budget *Budg;
	Budg = (Budget*)malloc(sizeof(Budget)*(NumBudget+1));
	if (!Budg)//分配失败
		exit(-1);
	for (int i = 0; i <= NumBudget; i++)
	{/*初始化每个桶*/
		Budg[i].NumElement = 0;
		Budg[i].Li = NULL;
	}
	int i = 0;
	while (i<L->Length)
	{/*依次读入每个元素,插入到相应的桶的链表第一个位置*/
		List *p;
		p= (List*)malloc(sizeof(List));//为链表申请一个节点空间
		if (!p)
			exit(-1);
		p->data = L->data[i];
		p->next = Budg[L->data[i]].Li;
		Budg[L->data[i]].Li = p;//桶的链表头变成p
		Budg[L->data[i]].NumElement++;//桶中的元素数量加1
		i++;
	}
	int j=0;
	List *p;
	for (int i = 0; i <=NumBudget; i++)
	{/*将桶中的数据取出来按顺序放入原顺序表*/
		p = Budg[i].Li;//链表头指针
		while (p)
		{
			L->data[j++] = p->data;
			p = p->next;
		}
	}
}

void radix_Sort(SqList *L)
{/*基数排序,次数优先,如果是十进制数,那么就建立10个桶*/
	typedef struct//定义桶
	{
		ElementType data[BudgetSize];
		int NumElement;//桶中元素个数
	}Budget;

	typedef struct 
	{
		Budget Budg[10];
	} Pass;

	Pass pass_single;//个位,十个桶每个桶里存放个位数为i的数据
	Pass pass_decade;//十位
	Pass pass_hundred;//百位
	Budget pass[10];
	for (int i = 0; i < BudgetSize; i++)//初始化
	{
		pass_single.Budg[i].NumElement = 0;
		pass_decade.Budg[i].NumElement = 0;
		pass_hundred.Budg[i].NumElement = 0;
	}

	int m;
	for (int i = 0; i < L->Length; i++) //按个位入桶
	{
		int single = L->data[i] % 10;//求出各个位数
		m = pass_single.Budg[single].NumElement;//当前桶内元素个数
		pass_single.Budg[single].data[m] = L->data[i];
		pass_single.Budg[single].NumElement++;
	}

	int n;
	for (int i = 0; i < 10; i++)//把数从个位pass的各桶中取出来,放入pass_decade的桶
	{
		for (int j = 0; j < pass_single.Budg[i].NumElement; j++)
		{
			int decade = (pass_single.Budg[i].data[j]/10 )%10;//求十位数
			n=pass_decade.Budg[decade].NumElement;
			pass_decade.Budg[decade].data[n] = pass_single.Budg[i].data[j];
			pass_decade.Budg[decade].NumElement++;
		}
	}
	int k1;
	for (int i = 0; i < 10; i++)//把数从十位pass的各桶中取出来,放入百位桶
	{
		for (int j = 0; j < pass_decade.Budg[i].NumElement; j++)
		{
			int hundred = pass_decade.Budg[i].data[j] / 100;//求百位数
			k1 = pass_hundred.Budg[hundred].NumElement;
			pass_hundred.Budg[hundred].data[k1] = pass_decade.Budg[i].data[j];
			pass_hundred.Budg[hundred].NumElement++;

		}
	}
	
	int k2 =0;
	for (int t = 0; t < 10; t++)//把数从百位pass的各桶中取出来,放入顺序表List
	{
		for (int j = 0; j < pass_hundred.Budg[t].NumElement; j++)
		{
			L->data[k2++] = pass_hundred.Budg[t].data[j];
		}
	}



}

int main()
{
	int A[] = { 200,51,123,3,5,234,126,233,45,78,1,0 };
	int i, len;
	len = sizeof(A) / sizeof(A[0]);
	SqList L, L1, L2;
	for (size_t i = 0; i < len; i++)
	{
		L.data[i] = A[i];
	}
	L.Length = len;
	L1 = L2 = L;
	printf("排序前:\n");
	DisplaySqList(L);
	Budget_Sort(&L);
	printf("桶排序后:\n");
	DisplaySqList(L);
	printf("基数排序后:\n");
	radix_Sort(&L1);
	DisplaySqList(L1);
	
}

运行结果:
在这里插入图片描述

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

XIE_QAID

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值