箱排序
1.例子和運行結果
例子:
運行結果:
2.排序思想
1.每個數都是由0-9組成,開始創建10個箱子(序號0-9).
2.對待排序進行遍歷,按照待排序個位數有序的添加對應箱子中,注意,是有序的添加.(這個可以使用快速排序,直接插入,選擇插入…等).
3.順序遍歷所有的箱子.然後順序的讀取箱子中的值,順序存儲到數組中,此時這個數組就是有序的數組
注意:這裏最多創建了10個箱子,如果知道了都是兩位數,也可以創建0-99號箱子,每個箱子後面添加對應的值.(這種方法不推薦,浪費內存)
3.算法實現
3.1定義數據結構
//箱子後面鏈接的順序表
typedef struct Seq{
//順序的值,這裏最多存儲MAX個數,所以待排序數的也不可以超過MAX個.(擴展的基數排序中,用鏈表,就不用考慮個數了)
int array[MAX];
int length;//當前順序表的長度
}BoxSeq;
//箱子排序的Bean
typedef struct Box{
int key;//排序的基數
BoxSeq seq;//箱子中順序存儲的數據(有序添加)
}B;
這裏可以進行完善有兩點:
1.可以將Seq和Box合併成一個,這個爲了便於理解箱子的結構,所以這樣定義的
2.箱子中的列表可以使用鏈表進行存儲,這樣就不用限制待排序的數量.這個在下面擴展的基數排序算法中進行了修改.
3.2 定義操作方法
/打印箱子
void logB(B box);
//往箱子中順序添加數值,遞增
void addValueToBox(B *b,int value);
//箱排序
void BoxSort(void);
3.3方法實現
//打印箱子
void logB(B box){
int i;
printf("[%d]->[",box.key);
for(i=0;i<box.seq.length;i++){
if(i==0)
printf("%d",box.seq.array[i]);
else
printf(",%d",box.seq.array[i]);
}
printf("]\n");
}
//往箱子中順序添加數值,遞增
void addValueToBox(B *b,int value){
//1.先找到插入的位置(找到第一個小於的value值的位置).
//10,13,15,17,比如要插入14,那麼找到的位置就是2.
int i=0;
int j;
while (i<b->seq.length&&b->seq.array[i]!=-1) {
if(b->seq.array[i]<value)
i++;
else
break;
}
//2.移動i位置之後(包含i位置)之後的值
//10,13,14,15,17
for(j=b->seq.length-1;j>=i;j--)
b->seq.array[j+1]=b->seq.array[j];
//3.將添加的值(value)添加到i位置
b->seq.array[i]=value;
//4.然後length+1
b->seq.length=b->seq.length+1;
}
//箱排序
void BoxSort(){
int i;
int count;
int j;
//1.初始化待排序的數組
int array[MAX];//待排序的數組
array[0]=88;
array[1]=19;
array[2]=13;
array[3]=78;
array[4]=43;
array[5]=15;
array[6]=22;
array[7]=16;
array[8]=83;
array[9]=10;
printf("待排序:");
logArray(array, MAX);
//2.因爲待排序的數組是0-100之間,所以我們定義10個箱子
B boxs[MAX];//箱子列表
//num存儲在箱子Bbox[num/10]中,添加的時候順序添加.
//初始化箱子列表
for(i=0;i<MAX;i++){
boxs[i].key=i;
boxs[i].seq.length=0;
for(j=0;j<MAX;j++){
boxs[i].seq.array[j]=-1;
}
}
//3.遍歷待排序數組
for(i=0;i<MAX;i++){
int bnum=array[i]/10;
//3.1.然後往對應的箱子中添加
addValueToBox(&boxs[bnum],array[i]);
}
count=0;
//4.遍歷箱子,組裝成有序數組
for(i=0;i<MAX;i++){
//4.1如果此時的箱子長度不爲空
//打印所有箱子中的數據
logB(boxs[i]);
if(boxs[i].seq.length>0){
//4.2.遍歷當前箱子然後順序輸出,添加到數組中
for(j=0;j<boxs[i].seq.length;j++)
array[count++]=boxs[i].seq.array[j];
}
}
//5.打印排序好的數組
printf("已排序:");
logArray(array, MAX);
}
3.5公共方法
//打印數組
void logArray(int array[],int length);
//打印數組
void logArray(int array[],int length){
int i;
printf("[");
for(i=0;i<length;i++){
if(i==0)
printf("%d",array[i]);
else
printf(",%d",array[i]);
}
printf("]\n");
}
基數排序
1.例子和運行結果
例子:
運行結果:
2.排序思想
1.基數排序是在箱排序的基礎之上進行擴展和完善的
2.通過判斷待排序的數組中的位數,決定進行創建箱子的個數和遍歷的次數.
例如:待排序中最多的位數爲3位,那麼就需要創建三個箱子(當然也可以創建兩個,進行復用,記得複用之前要清除之前的箱子),這裏我就不復用了.那麼需要進行遍歷三次
3.開始排序(就是遍歷裝箱操作)
3.1:第一次遍歷待排序的數組.進行第一次裝箱(箱子A),按照個數進行裝到對應的箱子.
3.2:第二次順序遍歷前面的箱子(箱子A),進行第二次裝箱(箱子B),按照十位數進行裝到對應的箱子中.
3.3:第三次順序遍歷前面的箱子(箱子B),進行第三次裝箱(箱子C),按照百位數進行裝到對應的箱子中.
到了這裏已經排序完成,還差最後一步.
4.組裝數據,順序遍歷最後一次的箱子(箱子C).存儲到一個數組中,此時數組中的數據就是已經排序好的.
例如:上面的箱子,順序遍歷這個箱子A存儲到箱子B中.(按照十位存儲)
讀取0號桶:
第一個數:200, 十位爲0, 存儲箱子B中0號桶[200]
第二個數:100, 十位爲0, 存儲箱子B中0號桶[200,100]
讀取1號桶:
第一個數:211, 十位爲1, 存儲箱子B中1號桶[211]
讀取2號桶:
沒有值跳過
讀取3號桶:
第一個數:143, 十位爲4, 存儲箱子B中4號桶[143]
第二個數:433, 十位爲3, 存儲箱子B中3號桶[433]
讀取4號桶:
第一個數:84, 十位爲4, 存儲箱子B中8號桶[84]
第二個數:134, 十位爲3, 存儲箱子B中3號桶[433,134]
第三個數:534, 十位爲3, 存儲箱子B中3號桶[433,134,534]
第四個數:994, 十位爲9, 存儲箱子B中9號桶[994]
…後面的就不一一舉例了.直到遍歷結束.
3.算法實現
3.1定義數據結構
#define MAX_COUNT 10
//鏈表結點 順序存儲箱子中數值,這樣就可以不用限制數據量.
typedef struct SNode{
int value;
struct SNode * next;
}Node;
//箱子中的每個鏈表
typedef struct List{
int key;
Node *header;//頭指針
Node *rear;//尾指針
}LinkList;
//箱子列表
typedef struct RadixBox{
LinkList * boxs[MAX_COUNT];
}RB;
3.2 定義方法
//入隊
void InsertList(LinkList *list,int value);
//打印隊列
void logList(LinkList *list);
//打印箱子
void logRadixBox(RB rb);
//打印箱子--數組類型
void logRadixBoxArray(RB rb);
//裝箱操作
//type:1->除數爲1*10 2:除數爲2*20
void EnRadixBox(int type,RB rb,int value);
//基數排序
void RadixSort(void);
下載的源碼中少了這個方法:logRadixBoxArray(),可以添加上,也可以不加,這是多打印了每次裝箱後的數組.
3.3方法實現
//打印隊列
void logList(LinkList *list){
//先判斷列表是否爲空
if(list!=NULL){
Node *p=list->header;
printf("[");
int first=1;
while (p!=NULL) {
if(first==1){
first=0;
printf("%d",p->value);
}else{
printf(",%d",p->value);
}
p=p->next;
}
printf("]\n");
}
}
//打印箱子
void logRadixBox(RB rb){
printf("********************************\n");
int i;
for(i=0;i<MAX_COUNT;i++){
printf("[%d]->",rb.boxs[i]->key);
logList(rb.boxs[i]);
}
logRadixBoxArray(rb);
printf("********************************\n");
}
//打印箱子--數組類型
void logRadixBoxArray(RB rb){
Node *p;
int i=0;
int j;
printf("裝箱後的數組:[");
for(j=0;j<MAX_COUNT;j++){
p= rb.boxs[j]->header;
while (p!=NULL) {
if(i==0)
{
printf("%d",p->value) ;
i=1;
}
else
printf(",%d",p->value) ;
p=p->next;
}
}
printf("]\n");
}
//入隊
void InsertList(LinkList *list,int value){
//1.創建插入的結點
Node *p=(Node *)malloc(sizeof(Node));
p->value=value;
p->next=NULL;
//2.判斷鏈表是否爲NULL
if(list==NULL){
list=(LinkList *)malloc(sizeof(LinkList));
list->header=NULL;
list->rear=NULL;
}
//3.將新的結點插入鏈表
if(list->header==NULL){
list->header=p;
}
if(list->rear==NULL){
list->rear=p;
}else{
list->rear->next=p;
list->rear=p;
}
}
//裝箱操作
//type->0:個數,1:十位,2:百位的餘數
void EnRadixBox(int type,RB rb,int value){
//1.type必須從1開始
if(type<0){
return;
}
//2.計算位置
//134: 134%10
//134: (134/10)%10
//134: (134/100)%10
//(value/(pow(10,type)))%10
int position= ((int) (value/(int)pow(10, type)))%10;
LinkList *list= rb.boxs[position];
InsertList(list,value);
}
//基數排序
void RadixSort(void){
int i;
int j;
int n=19;
//1.初始化待排序的數組
int array[]={76,84,134,196,177,143,696,534,599,211,433,200,994,459,635,179,100,26,284};
printf("未排序:");
logArray(array, n);
//2.首先要知道數組中最大的是幾位數,就需要幾個箱子,從個位到最高位順序裝箱
//初始化箱子
RB rbs[3];
//初始化三個箱子
for(i=0;i<3;i++){
for(j=0;j<MAX_COUNT;j++){
rbs[i].boxs[j]=(LinkList *)malloc(sizeof(LinkList));
rbs[i].boxs[j]->key=j;
rbs[i].boxs[j]->header=NULL;
rbs[i].boxs[j]->rear=NULL;
}
}
//3.開始裝箱
for(i=0;i<3;i++){
if(i==0){//第一次是遍歷排序數組,裝箱
for(j=0;j<n;j++){
//個位
EnRadixBox(i,rbs[i],array[j]);
}
logRadixBox(rbs[i]);
}else{//之後就是遍歷前一個箱子進行裝箱
//遍歷前一個箱子,裝在當前箱子
RB rbPre=rbs[i-1];
for(j=0;j<MAX_COUNT;j++){
if(rbPre.boxs[j]!=NULL){
Node *p=rbPre.boxs[j]->header;
while (p!=NULL) {
EnRadixBox(i,rbs[i],p->value);
p=p->next;
}
}
}
logRadixBox(rbs[i]);
}
}
//4.遍歷最後一個箱子裝入數組,就是排好序的
Node *p;
i=0;
for(j=0;j<MAX_COUNT;j++){
p= rbs[2].boxs[j]->header;
while (p!=NULL) {
array[i++]=p->value;
p=p->next;
}
}
printf("已排序:");
logArray(array, n);
}
3.4 另外的實現思路
我這裏循環遍歷的時候,第一次是遍歷待排序的數據,然後進行裝箱,剩下的順序遍歷,是遍歷上一次的箱子.
優化點:
1.創建箱子的時候,可以創建一個個箱子
2.每次裝完箱子操作後,可以先順序遍歷箱子,順序存儲到數組中.然後下一次遍歷的時候,是遍歷裝箱後的數組.這樣就是每次都是遍歷數組,進行裝箱.
3.在決定循環幾次的時候,我這裏知道待排序中的數組,最大的是3位數,
3.1這裏可以寫一個快速查找方法,尋找最大位數,或者最大值.
3.2或者是在第一次裝箱的時候,同時查找最大位數(N)也可以,這樣後面循環的就是再進行(N-1)次.