键索引计数法

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

//键索引计数法

#define KEY_BASE 5

typedef struct
{
    char *pString;  //条目字符串内容
    int   key;      //条目的归类键值,比如张三属于1类等
} S_ELEMENT;

//键索引计数法关键流程
//1、频率统计
//2、将频率转换为索引
//3、数据分类
//4、回写
void keyIndex(S_ELEMENT array[], int arrayCount, int keyBase)
{
    int i = 0;
    int *pCount = NULL;
    S_ELEMENT *pAux = NULL; 

    //分配计数资源
    //keyBase是键值基数,比如当前测试程序的分类键值范围是0~4,则是键键基数为5
    //这里在分配资源时会加1,主要为第2步算法做准备,细节在下面说明。
    pCount = (int *)malloc(sizeof(int) * (keyBase + 1));
    if ( pCount == NULL )
    {
        goto KEY_INDEX_EXIT; 
    }
    memset(pCount, 0, sizeof(int) * (keyBase + 1));

    //分配辅助数据资源
    pAux = (S_ELEMENT *)malloc(sizeof(S_ELEMENT) * arrayCount);
    if ( pAux == NULL )
    {
        goto KEY_INDEX_EXIT; 
    }
    memset(pAux, 0, sizeof(S_ELEMENT) * arrayCount);

    //1、频率统计,即统计同分类键的条目数
    //这里不使用数组索引0,而是从索引1开始,即分类键0的统计放在数组索引1处,
    //分类键1的统计放在数组索引2处,主要为第2步算法做准备,细节在下面说明。
    for ( i = 0; i < arrayCount; i++ ) 
    {
        pCount[array[i].key + 1]++;
    }

    //2、将频率转换为索引,其作用就是根据不同分类键的个数,依次得到不同分
    //类键的起始索引。
    //比如第0分类的条目数为6个,第1分类的条目数为8个,则pCount[0]最终值为0,
    //pCount[1]最终值为6,pCount[2]最终值为14
    //
    //000000111111112...
    //^     ^       ^
    //|     |       |
    //p[0] p[1]    p[2]
    //
    //之前在上面分配资源及进行统计时都从索引1开始进行处理,主要是用于方便这
    //一步算法流程,因为第0分类的起始索引一定为0,所以在这一步算法中直接从
    //分类1开始处理,比如当前i为0,pCount[0]记载了分类0的起始索引,pCount[1]
    //原值记载了分类0的条目数,pCount[1] = pCount[1] + pCount[0]则表示了此
    //时分类1的起始索引就是分类0的起始索引加上分类0的条目数。
    for ( i = 0; i < keyBase; i++ )
    {
        pCount[i+1] += pCount[i];
    }

    //3、数据分类,根据第2步pCount记载的统计排序后每个分类的起始索引位置,将
    //原始数据依次存储到临时数组正确的位置。
    for ( i = 0; i < arrayCount; i++ )
    {
        int index = pCount[array[i].key]++;
        memcpy(&pAux[index], &array[i], sizeof(S_ELEMENT));
    }

    //4、回写,最终将排序好的临时数组在写入原数组中。
    memcpy(array, pAux, sizeof(S_ELEMENT) * arrayCount);

KEY_INDEX_EXIT:
    if ( pCount != NULL )
    {
        free(pCount); 
    }
    if ( pAux != NULL )
    {
        free(pAux); 
    }
}

void dumpArray(S_ELEMENT array[], int arrayCount)
{
    int i = 0;

    for ( i = 0; i < arrayCount; i++ )
    {
        printf("[%03d] string %-10s, key %d\r\n", \
            i, array[i].pString, array[i].key); 
    }
}

int main()
{
    S_ELEMENT array[] = {
        { "Anderson",   2}, 
        { "Brown",      3}, 
        { "Davis",      3}, 
        { "Garcia",     4}, 
        { "Harris",     1}, 
        { "Jacksn",     3}, 
        { "Jones",      4}, 
        { "Martin",     3}, 
        { "Martinez",   1}, 
        { "Miller",     2}, 
        { "Moore",      0} 
    };

    int arrayCount = sizeof(array) / sizeof(array[0]);

    keyIndex(array, arrayCount, KEY_BASE);

    dumpArray(array, arrayCount);

    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值