您的位置:首页 > 其它

排序算法总结:一、基数排序

2015-07-15 17:25 537 查看
基数排序(Radix sort)是一种非比较型的整数排序算法,其原理是将整数按位数切割成不同的数字,然后按每个位数分别比较。
基数排序也分为LSD(Least significant digital)和MSD(Most significant digital)两种方式,LSD的排序方式由键值的最右边开始,而MSD则相反,由键值的最左边开始。

以LSD为例,假设原来有一串数值如下所示:
  73, 22, 93, 43, 55, 14, 28, 65, 39, 81

  首先根据个位数的数值,在走访数值时将它们分配至编号0到9的桶子中:
  0->NULL
  1->81->NULL
  2->22->NULL
  3->73->93->43->NULL
  4->14->NULL
  5->55->65->NULL
  6->NULL
  7->NULL
  8->28->NULL
  9->39->NULL

  接下来将这些桶中的数值重新串接起来,成为以下的数列:
  81, 22, 73, 93, 43, 14, 55, 65, 28, 39

  接着再进行一次分配,这次是根据十位数来分配:
  0->NULL
  1->14->NULL
  2->22->28->NULL
  3->39->NULL
  4->43->NULL
  5->55->NULL
  6->65->NULL
  7->73->NULL
  8->81->NULL
  9->93->NULL

  接下来将这些桶中的数值重新串接起来,成为以下的数列:
  14, 22, 28, 39, 43, 55, 65, 73, 81, 93

  这时候整个数列已经排序完毕;如果排序的对象有三位数以上,则持续进行以上的动作直至最高位数为止。

可以看到,我们使用了单链表来实现向桶中添加数组元素的功能,下面是具体的c语言实现:

单链表头文件定义:

#ifndef _List_H
#define _List_H

struct Node;
typedef int ElementType;
typedef struct Node* PtrToNode;
typedef PtrToNode List;
typedef PtrToNode Position;

List MakeEmpty(List L);
int IsEmpty(List L);
int IsLast(Position P, List L);
Position Find(ElementType X, List L);
Position FindLast(List L);
void Delete(ElementType X, List L);
Position FindPrevious(ElementType X, List L);
void Insert(ElementType X, List L, Position P);
void Append(ElementType X, List L);
void DeleteList(List L);
Position Header(List L);
Position First(List L);
Position Advance(Position P);
ElementType Retrieve(Position P);

#endif

struct Node
{
ElementType Element;
Position Next;
};


单链表的实现:

#include "List.h"
#include <stdio.h>
#include <stdlib.h>

void FatalError(char* c);

//测试链表是否为空(只有一个头指针)
//时间复杂度为O(1)
int IsEmpty(List L)
{
return L->Next == NULL;
}

//测试当前位置是否是链表的末尾
//时间复杂度为O(1)
int IsLast(Position P, List L)
{
return P->Next == NULL;
}

//寻找链表L中节点值为X的位置
//时间复杂度为O(N)
Position Find(ElementType X, List L)
{
Position P;

P = L->Next;
while(P != NULL && P->Element != X)
{
P = P->Next;
}

return P;
}

//寻找并返回节点值为X的前置节点的位置
//时间复杂度为O(N)
Position FindPrevious(ElementType X, List L)
{
Position P;

P = L;
while(P->Next != NULL && P->Next->Element != X)
{
P = P->Next;
}
return P;
}

//寻找链表中最后一个节点的位置
//时间复杂度为O(N)
Position FindLast(List L)
{
Position P;

P = L;
while(P->Next != NULL)
{
P = P->Next;
}
return P;
}

//在链表L中删除节点值为X的节点
//时间复杂度为O(N)
void Delete(ElementType X, List L)
{
Position P, TmpCell;

P = FindPrevious(X, L);

if(!IsLast(P, L))
{
TmpCell = P->Next;
P->Next = TmpCell->Next;
free(TmpCell);
}
}

//在单链表L中,将节点X插入到位置P的后面
//时间复杂度为O(1)
void Insert(ElementType X, List L, Position P)
{
Position TmpCell;

TmpCell = malloc(sizeof(struct Node));
if(TmpCell == NULL)
{
FatalError("Out of space!!");
return;
}

TmpCell->Element = X;
TmpCell->Next = P->Next;
P->Next = TmpCell;
}

//将节点插入到链表最后面的位置
//时间复杂度为O(N)
void Append(ElementType X, List L)
{
Insert(X, L, FindLast(L));
}

//删除全部链表,只留下头节点。
//时间复杂度为O(N)
void DeleteList(List L)
{
Position P, temp;

P = L->Next;
L->Next = NULL;

while(P != NULL)
{
temp = P->Next;
free(P);
P = temp;
}
}

void FatalError(char* c)
{
printf("Fatal Error: %s\n", c);
}


基数排序算法的实现:

#include <stdio.h>
#include <stdlib.h>
#include "List.h"

#define sizeOfArray 10

int* RadixSort(int*, int, int);
void PrintAll(int*, int );
void RebuildListHeaderArray(PtrToNode*, int );

int main(void)
{
int inputData[] = {73, 22, 393, 43, 255, 14, 28, 65, 39, 181};
int *newInputData;

printf("Initial:\n");
PrintAll(inputData, sizeOfArray);

newInputData = RadixSort(inputData, sizeOfArray, 3);

printf("Final:\n");
PrintAll(newInputData, sizeOfArray);

return 1;
}

//基数排序的时间复杂度是 O(k·n),其中n是排序元素个数,k是数字位数。
int* RadixSort(int inputData[], int arrayLength, int digitLength)
{
int i, j, k, div;
PtrToNode headerArray[arrayLength];

//Initialize
for(i=0; i<arrayLength; i++)
{
//Make a header first
PtrToNode header = malloc(sizeof(struct Node));
header->Element = i;
header->Next = NULL;

headerArray[i] = header;
}

//Insert List
for(i=0, div=1; i<digitLength; i++, div=div*10)
{
for(j=0; j<arrayLength; j++)
{
//Fetch a header first
PtrToNode header = headerArray[inputData[j] / div % 10];

//Insert into list
Append(inputData[j], header);
}

//Regenerate array
int index = 0;
for(k=0; k<arrayLength; k++)
{
Position p = headerArray[k];
while(p->Next != NULL)
{
p = p->Next;
inputData[index] = p->Element;
index++;
}
}
printf("The %d pass result:\n", i+1);
PrintAll(inputData, 10);
RebuildListHeaderArray(headerArray, 10);
}
return inputData;
}

void PrintAll(int *p, int arrayLength)
{
int i;
for(i=0; i<arrayLength; i++)
{
printf("%d, ", *(p+i));
}
printf("\n");
}

void RebuildListHeaderArray(PtrToNode headerArray[], int arrayLength)
{
int i;
for(i=0; i<arrayLength; i++)
{
DeleteList(headerArray[i]);
}
}


输出结果如下:
Initial:
73, 22, 393, 43, 255, 14, 28, 65, 39, 181,

The 1 pass result:
(按个位数排序)
181, 22, 73, 393, 43, 14, 255, 65, 28, 39,

The 2 pass result:
(按十位数排序)
14, 22, 28, 39, 43, 255, 65, 73, 181, 393,

The 3 pass result:
(按百位数排序)
14, 22, 28, 39, 43, 65, 73, 181, 255, 393,

Final:
14, 22, 28, 39, 43, 65, 73, 181, 255, 393,

可以看到在经过三趟排序后,算法结束。时间复杂度是O(digitLength*arrayLength), 也就是算法所用时间与输入元素中的最高位数与输入的元素数的乘积成正比。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: