线性时间排序
前面介绍的几种排序,都是能够在复杂度nlg(n)时间内排序n个数的算法,这些算法都是通过比较来决定它们的顺序,这类算法叫做比较排序 。下面介绍的几种算法用运算去排序,且它们的复杂度是线性时间。
——————————————————————————————————————
1.计数排序
计数排序采用的方法是:对每个元素x,去确定小于x的元素的个数,从而就可以知道元素x在输出数组中的哪个位置了。
计数排序的一个重要性质是它是稳定的,即对于相同的两个数,排序后,还会保持它们在输入数组中的前后顺序,这也是下面基数排序的基础。
虽然复杂度比之间的算法减小了,但在算法实现过程中,它要求输入数组数据位于一个区间[0,k]内,因为要遍历数组,计算[0,k]间的每个数在输入数组中的个数,这也算是计数排序的缺点吧!
下面是调试的程序,可直接运行,详细过程看下《算法导论》
#include<STDIO.H> #define K 10 //数据在[0,K]之间 int A[]={2,7,3,5,3,2,9}; int B[20]={0}; //输出数组 int C[20]={0}; //计数数组 int Length=sizeof(A)/sizeof(A[0])-1; void Count_Sort(int *A,int *B,int k) { int j; for (j=0;j<=Length;j++) //为每个数计个数 { C[A[j]]=C[A[j]]+1; } for (j=1;j<=K;j++) //计算有多少元素小于等于j { C[j]=C[j]+C[j-1]; } for (j=Length;j>=0;j--) //倒叙输出数组,保证了数据是稳定的 { B[C[A[j]]]=A[j]; C[A[j]]=C[A[j]]-1; //A[j]输出,对应计数数组元素减1。 } } int main() { int i; Count_Sort(A,B,K); for (i=1;i<=Length+1;i++) { printf("%3d",B[i]); } printf("\n"); return 0; }
———————————————————————————————————
2.基数排序
基本思想:对N个d位的数据排序,与传统的想法不同,它是先从最低有效位开始排。
这里必须保证每次排序是稳定的,即对相同的数据,输出的顺序必须与输入的顺序相同。
实现例程:
#include <STDIO.H> #include <string.h> int A[]={329,457,657,839,436,720,355}; //要排序的数组 int Length=sizeof(A)/sizeof(A[0])-1; void Count_Sort(int *A2,int *B) //计数排序 { int j; int C[10]={0}; //计数数组,数字在[0,9]之间 for (j=0;j<=Length;j++) //为每个数计个数 { C[A2[j]]=C[A2[j]]+1; } for (j=1;j<=10;j++) //计算有多少元素小于等于j { C[j]=C[j]+C[j-1]; } for (j=Length;j>=0;j--) //倒叙输出数组,保证了数据是稳定的 { B[C[A2[j]]]=A[j]; //参照C[A2[j]]的大小,对数组A[j]输出 C[A2[j]]=C[A2[j]]-1; } } void Radix_Sort(int *A,int d) { int i,j,k,temp; int A2[10]={0}; //存放各个位 int B[20]={0}; //输出数组 for(i=1;i<=d;i++) { for (j=0;j<=Length;j++) { temp=A[j]; k=i; while(k>1) { temp=temp/10; k--; } A2[j]=temp%10; //取指定的位存到A2[j],等待排序 } Count_Sort(A2,B); memcpy(A,&B[1],(Length+1)*4); } } int main() { int j; Radix_Sort(A,3); for (j=0;j<=Length;j++) { printf("%5d\n",A[j]); } }
———————————————————————————————————————————————————————————————————————————
3.桶排序
桶排序是假设输入数据服从均匀分布,平均情况下也是线性时间。假设输入数据是由一个随机过程产生,该过程将元素均匀,独立地分布在[0,1)区间上。
它将[0,1)区间划分为n个相同大小的子区间,称为“桶”,然后遍历输入的数据,分别放入到指定的桶中(放入桶中的同时,有个链表插入排序的过程)。最后依次把各个桶中数据输出即可。
例程:
#include <STDIO.H> #include <STDLIB.H> int A[]={78,17,39,26,72,94,21,12,23,68};//假如输入数据平均分布在[0,99]区间内 int Length = sizeof(A)/sizeof(A[0])-1; typedef struct Node //链表单元结构 { int num; struct Node *next; }Node; Node *Bucket[10]={0}; //分成10个桶,即10个小区间 void Bucket_Sort(int *A) { int i; int a; Node * temp=NULL,*Pre_temp=NULL; for (i=0;i<=Length;i++) //遍历输入数组,放入到指定的桶中 { a = (int)(A[i]/10); if(Bucket[a] == 0) { Bucket[a]=(Node *)malloc(sizeof(Node)); Bucket[a]->num=A[i]; Bucket[a]->next=NULL; } else //对非空链表插入排序 { temp=Pre_temp=Bucket[a]; while(A[i] > temp->num) { Pre_temp=temp; temp=temp->next; if (temp==NULL) break; } if (temp == NULL) // 插入到最后一个位置 { temp=(Node *)malloc(sizeof(Node)); temp->num=A[i]; temp->next=NULL; Pre_temp->next=temp; } else if (temp == Bucket[a]) //插入到第一个位置 { temp=(Node *)malloc(sizeof(Node)); temp->num=A[i]; temp->next=Bucket[a]; Bucket[a]=temp; } else //插入到中间位置 { temp=(Node *)malloc(sizeof(Node)); temp->num=A[i]; temp->next=Pre_temp->next; Pre_temp->next=temp; } } } } void Free_List(Node * head) //释放链表结构内存 { Node *N=head; while (head!=NULL) { N=head->next; free(head); head=N; } } int main() { Node * temp=NULL; int i=1; Bucket_Sort(A); for(i=0;i<=9;i++) //依次输出各个桶中的数据 { temp=Bucket[i]; while(temp!=NULL) { printf("%3d\n",temp->num); temp=temp->next; } Free_List(Bucket[i]); //释放第i个桶的内存 } return 0; }
时间: 2024-10-11 15:51:27