zoukankan      html  css  js  c++  java
  • 排序算法总结:一、基数排序

    基数排序(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语言实现:

    单链表头文件定义:

     1 #ifndef _List_H
     2 #define _List_H
     3  
     4 struct Node;
     5 typedef int ElementType;
     6 typedef struct Node* PtrToNode;
     7 typedef PtrToNode List;
     8 typedef PtrToNode Position;
     9  
    10 List MakeEmpty(List L);
    11 int IsEmpty(List L);
    12 int IsLast(Position P, List L);
    13 Position Find(ElementType X, List L);
    14 Position FindLast(List L);
    15 void Delete(ElementType X, List L);
    16 Position FindPrevious(ElementType X, List L);
    17 void Insert(ElementType X, List L, Position P);
    18 void Append(ElementType X, List L);
    19 void DeleteList(List L);
    20 Position Header(List L);
    21 Position First(List L);
    22 Position Advance(Position P);
    23 ElementType Retrieve(Position P);
    24  
    25 #endif
    26  
    27 struct Node
    28 {
    29     ElementType Element;
    30     Position Next;
    31 };

    单链表的实现:

      1 #include "List.h"
      2 #include <stdio.h>
      3 #include <stdlib.h>
      4  
      5 void FatalError(char* c);
      6  
      7 //测试链表是否为空(只有一个头指针)
      8 //时间复杂度为O(1)
      9 int IsEmpty(List L)
     10 {
     11     return L->Next == NULL;
     12 }
     13  
     14 //测试当前位置是否是链表的末尾
     15 //时间复杂度为O(1)
     16 int IsLast(Position P, List L)
     17 {
     18     return P->Next == NULL;
     19 }
     20  
     21 //寻找链表L中节点值为X的位置
     22 //时间复杂度为O(N)
     23 Position Find(ElementType X, List L)
     24 {
     25     Position P;
     26  
     27     P = L->Next;
     28     while(P != NULL && P->Element != X)
     29     {
     30     P = P->Next;
     31     }
     32  
     33     return P;
     34 }
     35  
     36 //寻找并返回节点值为X的前置节点的位置
     37 //时间复杂度为O(N)
     38 Position FindPrevious(ElementType X, List L)
     39 {
     40     Position P;
     41  
     42     P = L;
     43     while(P->Next != NULL && P->Next->Element != X)
     44     {
     45     P = P->Next;
     46     }
     47     return P;
     48 }
     49  
     50 //寻找链表中最后一个节点的位置
     51 //时间复杂度为O(N)
     52 Position FindLast(List L)
     53 {
     54     Position P;
     55  
     56     P = L;
     57     while(P->Next != NULL)
     58     {
     59     P = P->Next;
     60     }
     61     return P;
     62 }
     63  
     64 //在链表L中删除节点值为X的节点
     65 //时间复杂度为O(N)
     66 void Delete(ElementType X, List L)
     67 {
     68     Position P, TmpCell;
     69  
     70     P = FindPrevious(X, L);
     71  
     72     if(!IsLast(P, L))
     73     {
     74     TmpCell = P->Next;
     75     P->Next = TmpCell->Next;
     76     free(TmpCell);
     77     }
     78 }
     79  
     80 //在单链表L中,将节点X插入到位置P的后面
     81 //时间复杂度为O(1)
     82 void Insert(ElementType X, List L, Position P)
     83 {
     84     Position TmpCell;
     85  
     86     TmpCell = malloc(sizeof(struct Node));
     87     if(TmpCell == NULL)
     88     {
     89     FatalError("Out of space!!");
     90     return;
     91     }
     92  
     93     TmpCell->Element = X;
     94     TmpCell->Next = P->Next;
     95     P->Next = TmpCell;
     96 }
     97  
     98 //将节点插入到链表最后面的位置
     99 //时间复杂度为O(N)
    100 void Append(ElementType X, List L)
    101 {
    102     Insert(X, L, FindLast(L));
    103 }
    104  
    105 //删除全部链表,只留下头节点。
    106 //时间复杂度为O(N)
    107 void DeleteList(List L)
    108 {
    109     Position P, temp;
    110  
    111     P = L->Next;
    112     L->Next = NULL;
    113  
    114     while(P != NULL)
    115     {
    116     temp = P->Next;
    117     free(P);
    118     P = temp;
    119     }
    120 }
    121  
    122 void FatalError(char* c)
    123 {
    124     printf("Fatal Error: %s
    ", c);
    125 }

    基数排序算法的实现:

     1 #include <stdio.h>
     2 #include <stdlib.h>
     3 #include "List.h"
     4  
     5 #define sizeOfArray 10
     6  
     7 int* RadixSort(int*, int, int);
     8 void PrintAll(int*, int );
     9 void RebuildListHeaderArray(PtrToNode*, int );
    10  
    11 int main(void)
    12 {
    13     int inputData[] = {73, 22, 393, 43, 255, 14, 28, 65, 39, 181};
    14     int *newInputData;
    15  
    16     printf("Initial:
    ");
    17     PrintAll(inputData, sizeOfArray);
    18  
    19     newInputData = RadixSort(inputData, sizeOfArray, 3);
    20  
    21     printf("Final:
    ");
    22     PrintAll(newInputData, sizeOfArray);
    23  
    24     return 1;
    25 }
    26  
    27 //基数排序的时间复杂度是 O(k·n),其中n是排序元素个数,k是数字位数。
    28 int* RadixSort(int inputData[], int arrayLength, int digitLength)
    29 {
    30     int i, j, k, div; 
    31     PtrToNode headerArray[arrayLength];
    32  
    33     //Initialize
    34     for(i=0; i<arrayLength; i++)
    35     {
    36     //Make a header first
    37     PtrToNode header = malloc(sizeof(struct Node));
    38     header->Element = i;
    39     header->Next = NULL;
    40  
    41     headerArray[i] = header;
    42     }
    43  
    44     //Insert List
    45     for(i=0, div=1; i<digitLength; i++, div=div*10)
    46     {
    47     for(j=0; j<arrayLength; j++)
    48     {
    49         //Fetch a header first
    50         PtrToNode header = headerArray[inputData[j] / div % 10];
    51  
    52         //Insert into list
    53         Append(inputData[j], header);
    54     }
    55  
    56     //Regenerate array
    57     int index = 0;
    58     for(k=0; k<arrayLength; k++)
    59     {
    60         Position p = headerArray[k];
    61         while(p->Next != NULL)
    62         {
    63         p = p->Next;
    64         inputData[index] = p->Element;
    65         index++;
    66         }
    67     }
    68     printf("The %d pass result:
    ", i+1);
    69     PrintAll(inputData, 10);
    70     RebuildListHeaderArray(headerArray, 10);
    71     }
    72     return inputData;
    73 }
    74  
    75 void PrintAll(int *p, int arrayLength)
    76 {
    77     int i;
    78     for(i=0; i<arrayLength; i++)
    79     {
    80     printf("%d, ", *(p+i));
    81     }
    82     printf("
    ");
    83 }
    84  
    85 void RebuildListHeaderArray(PtrToNode headerArray[], int arrayLength)
    86 {
    87     int i;
    88     for(i=0; i<arrayLength; i++)
    89     {
    90     DeleteList(headerArray[i]);
    91     }
    92 }

    输出结果如下:
    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), 也就是算法所用时间与输入元素中的最高位数与输入的元素数的乘积成正比。

  • 相关阅读:
    HDU2034:人见人爱A-B
    Codeup1085: 阶乘的和
    HDU2037:今年暑假不AC
    剑指Offer(Java版)第二十七题:从上往下打印出二叉树的每个节点,同层节点从左至右打印。
    剑指Offer(Java版)第二十六题:输入两个整数序列,第一个序列表示栈的压入顺序, 请判断第二个序列是否为该栈的弹出顺序。 假设压入栈的所有数字均不相等。 例如序列1、2、3、4、5是某栈的压栈序列, 序列5、4、3、2、1是该压栈序列对应的一个弹出序列, 但4、3、5、1、2就不可能是该压栈序列的弹出序列。
    剑指Offer(Java版)第二十五题:包含min函数的栈
    剑指Offer(Java版)第二十四题:顺时针打印矩阵
    MongoDB学习笔记10——分片
    MongoDB学习笔记9——复制
    MongoDB学习笔记8——优化
  • 原文地址:https://www.cnblogs.com/liupengblog/p/4648972.html
Copyright © 2011-2022 走看看