| 网站首页 | 业界新闻 | 小组 | 威客 | 人才 | 下载频道 | 博客 | 代码贴 | 在线编程 | 编程论坛
欢迎加入我们,一同切磋技术
用户名:   
 
密 码:  
共有 6876 人关注过本帖, 5 人收藏
标题:分享一份归并排序代码,欢迎测试改进
只看楼主 加入收藏
寒风中的细雨
Rank: 17Rank: 17Rank: 17Rank: 17Rank: 17
等 级:贵宾
威 望:66
帖 子:1710
专家分:8645
注 册:2009-9-15
结帖率:100%
收藏(5)
已结贴  问题点数:99 回复次数:20 
分享一份归并排序代码,欢迎测试改进
程序代码:
/**

 *\file merge_sort.h

 *\brief 归并排序

 *\date 2017/04/12

 */

#ifndef    __MERGE_SORT_H_2017_04_12__
#define    __MERGE_SORT_H_2017_04_12__

#ifdef     __cplusplus
extern "C"{
#endif


/**

 *\brief 归并排序中 设置merge_array的初始值

 *\param[in] len 待初始化的数据规模

 *\param[in] disoder_ary 等待排序的数据

 *\param[in] merge_ary 初始化的对象

 *\retval 1 初始化成功

 *\retval 0 初始化失败

 */
typedef int (*merge_set_fun)(unsigned int len, void *disoder_ary, void **merge_ary);

/**

 *\brief 归并排序中 两个元素对比函数

 *\param[in] cmp1 对比元素1

 *\param[in] cmp2 对比元素2

 *\retval 1 cmp1 > cmp2

 *\retval 0 cmp1 = cmp2

 *\retval -1 cmp1 < cmp2

 */
typedef int (*merge_cmp_fun)(void *cmp1, void *cmp2);

/**

 *\brief 归并排序中 赋值操作

 *\param[in] lopr 被赋值的 等号 左边的数

 *\param[in] ropr 赋值的 等号 右边的数

 *\retval 1 赋值成功

 *\retval 0 赋值失败 

 */
typedef int (*merge_agn_fun)(void **lopr, void *ropr);

/**

 *\brief 归并排序中 获取排序结果

 *\param[in] len 获取结果的数据规模

 *\param[in,out] res_ary 等待排序的数据

 *\param[in] merge_ary 归并排序后的结果

 *\retval 1 获取结果成功

 *\retval 0 获取结果失败

 */
typedef int (*merge_res_fun)(unsigned int len, void *res_ary, void **merge_ary);

/**

 *\brief 初始化归并排序环境

 *\param[in] len 待排序的规模

 *\param[in] disorder_array 待排序的数组

 *\param[in] f_set 设置merge_array初始值函数

 *\param[in] f_cmp 排序过程中需要的比较函数

 *\param[in] f_agn 赋值操作函数

 *\retval 1 初始化成功

 *\retval 0 初始化失败

 */
int merge_init(unsigned int len, void *disorder_array,
                merge_set_fun f_set, 
                merge_cmp_fun f_cmp, 
                merge_agn_fun f_agn);
                
/**

 *\brief 销毁

 */
void merge_destory(void);

/**

 *\brief 归并排序

 *\param[in] len 获取排序结果结果规模

 *\param[in,out] res_array 获取排序结果

 *\param[in] f_res 获取结果的回调

 */
void merge_sort(unsigned int len, void *res_array, merge_res_fun f_res);        

#ifdef    __cplusplus
}
#endif
#endif//__MERGE_SORT_H_2017_04_12__


程序代码:
/**

 *\file merge_sort.cc

 *\brief 归并排序

 *\date 2017/04/10

 */

#include "merge_sort.h"
#include <stdio.h>
#include <assert.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>


static void **s_merge_array = (void**)0;    ///< 交换的变量
static void **s_merge_swap = (void**)0;    ///< 临时交换区
static unsigned int merge_len = 0;    ///< 待排序的规模
static merge_cmp_fun mcmp_fun = NULL;    ///< 对比函数
static merge_agn_fun magn_fun = NULL;    ///< 赋值函数
static merge_set_fun mset_fun = NULL;    ///< 设置merge_array的初始值

/**

 *\brief 初始化归并排序环境

 *\param[in] len 待排序的规模

 *\param[in] disorder_array 待排序的数组

 *\param[in] f_set 设置merge_array初始值函数

 *\param[in] f_cmp 排序过程中需要的比较函数

 *\param[in] f_agn 赋值操作函数

 *\retval 1 初始化成功

 *\retval 0 初始化失败

 */
int merge_init(unsigned int len, void *disorder_array,
                merge_set_fun f_set, 
                merge_cmp_fun f_cmp, 
                merge_agn_fun f_agn)
{
    assert(len > 1);
    assert((void**)0 != disorder_array);    
    assert(NULL != f_set);
    assert(NULL != f_set);
    assert(NULL != f_set);    
    
    s_merge_array = (void **) malloc (sizeof(void*) * len);
    s_merge_swap = (void **) malloc (sizeof(void*) * len);
    if ((void**)0 == s_merge_array || (void**)0 == s_merge_swap){
        
        printf("malloc failed errno(%d)!\n", errno);
        if (s_merge_array){
            
            free(s_merge_array);
            s_merge_array = (void**)0;
        }
        
        if (s_merge_swap){
            
            free(s_merge_swap);
            s_merge_swap = (void**)0;            
        }
        
        return 0;
    }
    merge_len = len;
    
    mset_fun = f_set;
    mcmp_fun = f_cmp;
    magn_fun = f_agn;
    
    return mset_fun(len, disorder_array, s_merge_array);
}

/**

 *\brief 执行 归并排序

 *\param[in] beg 起始位置下标

 *\param[in] end 结束位置下标

 */
static void __msort(unsigned int beg, unsigned int end)
{
    unsigned int mid = 0;
    unsigned int i = 0, j = 0, k = 0;
    int ret = 0;
    
    assert (end >= beg);
    
    if (end - beg >= 1){
        
        mid = (end - beg) / 2;
        __msort(beg, beg + mid);
        __msort(beg + mid + 1, end);
        
        // 归并 [beg, beg + mid]  和 [beg + mid + 1, end] 两个有序单元
        for (i = beg, j = beg + mid + 1, k = beg; i <= beg + mid && j <= end; ++k){
            
            ret = mcmp_fun(s_merge_array[i], s_merge_array[j]);
            if (-1 == ret){
                
                magn_fun(&s_merge_swap[k], s_merge_array[i]);
                ++i;
            }else{
                
                magn_fun(&s_merge_swap[k], s_merge_array[j]);
                ++j;
            }
        }
        
        while (i <= beg + mid){    // 将剩余的全部拷贝
            
            magn_fun(&s_merge_swap[k], s_merge_array[i]);
            ++k;
            ++i;
        }
        
        while(j <= end){    // 将剩余的全部拷贝
            
            magn_fun(&s_merge_swap[k], s_merge_array[j]);
            ++k;
            ++j;
        }
        memcpy(&s_merge_array[beg], &s_merge_swap[beg], (end - beg + 1) * sizeof(void*));
    }else{
        
        // end == beg 表示只有一个, 不处理
    }    
}

/**

 *\brief 归并排序

 *\param[in] len 获取排序结果结果规模

 *\param[in,out] res_array 获取排序结果

 *\param[in] f_res 获取结果的回调

 */
void merge_sort(unsigned int len, void *res_array, merge_res_fun f_res)
{
    __msort(0, merge_len - 1);
    
    if (len <= 0 || NULL == res_array || NULL == f_res){// 不期望返回结果
    
        return;
    }
    
    len = len > merge_len ? merge_len : len;    // 取小的
    f_res(len, res_array, s_merge_array);
}

/**

 *\brief 销毁

 */
void merge_destory(void)
{
    if (s_merge_array){
        
        free(s_merge_array);
        s_merge_array = (void**)0;
    }
    
    if (s_merge_swap){
        
        free(s_merge_swap);
        s_merge_swap = (void**)0;            
    }    
    
    merge_len = 0;
    
    mset_fun = NULL;
    mcmp_fun = NULL;
    magn_fun = NULL;
}


程序代码:
/**

 *\file main.cc

 *\brief 归并排序

 *\date 2017/04/10

 */
#include "merge_sort.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <assert.h>
#include <errno.h>

static int s_len = 0;        ///< 待排序的数列长度
static int s_ary[10000];    ///< 存放数列

/** 

 *\brief 根据输入 随机创建

 */
static void creat_ary(void)
{
    int i = 0;
    
    printf("输入随机生成数列的数量:");
    scanf("%d", &s_len);
    
    assert(s_len > 1 && s_len < 10000);
    
    srand(time(0));
    
    for (i = 0; i < s_len; ++i){
            
        s_ary[i] = rand()%10000;
    }
}

/**

 *\brief 输出随机产生的数列

 */
static void print_ary(void)
{
    int i = 0;
    
    for (i = 0; i < s_len; ++i){
        
        printf("%d ", s_ary[i]);
    }
    printf("\n");
}

/**

 *\brief 归并排序中 设置merge_array的初始值

 *\param[in] len 待初始化的数据规模

 *\param[in] disoder_ary 等待排序的数据

 *\param[in] merge_ary 初始化的对象

 *\retval 1 初始化成功

 *\retval 0 初始化失败

 */
int set_fun(unsigned int len, void *disoder_ary, void **merge_ary)
{
    unsigned int i = 0;
    int *ary1 = NULL, **ary2 = NULL;
    
    assert((void**)0 != disoder_ary);
    assert((void**)0 != merge_ary);
    
    ary1 = (int *)disoder_ary;
    ary2 = (int **)merge_ary;
    
    for (i = 0; i < len; ++i){
        
        ary2[i] = &ary1[i];
    }
    
    return 1;
}

/**

 *\brief 归并排序中 两个元素对比函数

 *\param[in] cmp1 对比元素1

 *\param[in] cmp2 对比元素2

 *\retval 1 cmp1 > cmp2

 *\retval 0 cmp1 = cmp2

 *\retval -1 cmp1 < cmp2

 */
int cmp_fun(void *cmp1, void *cmp2)
{
    int *int_cmp1 = NULL;
    int *int_cmp2 = NULL;

    assert(NULL != cmp1);
    assert(NULL != cmp2);
    
    int_cmp1 = (int*)cmp1;
    int_cmp2 = (int*)cmp2;
    if (*int_cmp1 > *int_cmp2){
        
        return 1;
    }else if (*int_cmp1 == *int_cmp2){
        
        return 0;
    }
    
    return -1;
}

/**

 *\brief 归并排序中 赋值操作

 *\param[in] lopr 被赋值的 等号 左边的数

 *\param[in] ropr 赋值的 等号 右边的数

 *\retval 1 赋值成功

 *\retval 0 赋值失败 

 */
int agn_fun(void **lopr, void *ropr)
{
    int **int_lopr = NULL;
    int *int_ropr = NULL;
    
    assert((void**)0 != lopr);
    assert(NULL != ropr);
    
    int_lopr = (int **)lopr;
    int_ropr = (int *)ropr;
    *int_lopr = int_ropr;
    
    return 1;
}

/**

 *\brief 归并排序中 获取排序结果

 *\param[in] len 获取结果的数据规模 

 *\param[in,out] res_ary 等待排序的数据

 *\param[in] merge_ary 归并排序后的结果

 *\retval 1 获取结果成功

 *\retval 0 获取结果失败

 */
int get_res_fun(unsigned int len, void *res_ary, void **merge_ary)
{
    int *buf = NULL, **ary = (int**)0, *res = NULL;
    unsigned int i = 0;
    
    assert(0 <= len);
    assert(NULL != res_ary);
    assert((void**)0 != merge_ary);
    
    buf = (int*) malloc (len * sizeof(int));
    if (NULL == buf){
        
        printf("malloc failed, errno(%d)\n", errno);
        return 0;
    }
    ary = (int **)merge_ary;
    res = (int *)res_ary;
    
    for (i = 0; i < len; ++i){
        
        buf[i] = *ary[i];    // 取指针指向的内容
    }
    
    memcpy(res, buf, len * sizeof(int));
    
    return 1;
}

int main(int argc, char **argv)
{
    creat_ary();
    
    print_ary();
    
    merge_init(s_len, (void *)s_ary, set_fun, cmp_fun, agn_fun);
    
    merge_sort(s_len, (void *)s_ary, get_res_fun);
    
    merge_destory();
    
    print_ary();
    
    return 0;
}


[此贴子已经被作者于2017-4-21 01:11编辑过]

搜索更多相关主题的帖子: file color 
2017-04-21 01:07
寒风中的细雨
Rank: 17Rank: 17Rank: 17Rank: 17Rank: 17
等 级:贵宾
威 望:66
帖 子:1710
专家分:8645
注 册:2009-9-15
收藏
得分:0 
程序代码:
object = main.o merge_sort.o
target = merge_sort

CFLAGS = -g
CPPFLAGS = -g
CC = g++

$(target) : $(object)
    $(CC) -o $(target) $(object)
    
.PHONY: clean
clean:
    -rm $(target) $(object)


2017-04-21 01:09
寒风中的细雨
Rank: 17Rank: 17Rank: 17Rank: 17Rank: 17
等 级:贵宾
威 望:66
帖 子:1710
专家分:8645
注 册:2009-9-15
收藏
得分:0 
程序代码:
测试数据
$ ./merge_sort 
输入随机生成数列的数量:10
9531 3434 5417 3335 5834 8781 5040 1465 9707 4451 
1465 3335 3434 4451 5040 5417 5834 8781 9531 9707 
2017-04-21 01:10
marlow
Rank: 6Rank: 6
等 级:侠之大者
威 望:2
帖 子:125
专家分:419
注 册:2016-7-18
收藏
得分:33 
不错,非递归归并。还可以递归归并,排序过程中不复制记录,只调整指向记录的指针,速度会快一些。
整得有些眼花缭乱,其实归并排序没有那么复杂。。。

一切都在学习、尝试、摸索中
2017-04-21 07:53
yangfrancis
Rank: 16Rank: 16Rank: 16Rank: 16
等 级:贵宾
威 望:141
帖 子:1510
专家分:7661
注 册:2014-5-19
收藏
得分:33 
这种算法主要是两个子数列归并的时候蛮难的
2017-04-21 09:56
寒风中的细雨
Rank: 17Rank: 17Rank: 17Rank: 17Rank: 17
等 级:贵宾
威 望:66
帖 子:1710
专家分:8645
注 册:2009-9-15
收藏
得分:0 
回复 4楼 marlow
给出代码是递归实现的


实现看起来复杂  是为了让算法做到通用  做到不会因为排序的数据类型改变 而调整核心算法代码


2017-04-21 12:22
九转星河
Rank: 19Rank: 19Rank: 19Rank: 19Rank: 19Rank: 19
来 自:长长久久
等 级:贵宾
威 望:52
帖 子:5023
专家分:14003
注 册:2016-10-22
收藏
得分:33 
感觉很有价值~先收藏以后再慢慢看~

虽然感觉看懂的人不会太多~但还是置顶一下~~~

[code]/*~个性签名:bug是什么意思?bug是看上去没有可能的东西实际上是有可能做到的 就是这样~2018-08-08更~*/[/code]
2017-04-21 12:30
寒风中的细雨
Rank: 17Rank: 17Rank: 17Rank: 17Rank: 17
等 级:贵宾
威 望:66
帖 子:1710
专家分:8645
注 册:2009-9-15
收藏
得分:0 
回复 楼主 寒风中的细雨
int get_res_fun(unsigned int len, void *res_ary, void **merge_ary)


malloc 内存没有释放
2017-04-22 09:21
寒风中的细雨
Rank: 17Rank: 17Rank: 17Rank: 17Rank: 17
等 级:贵宾
威 望:66
帖 子:1710
专家分:8645
注 册:2009-9-15
收藏
得分:0 
回复 8楼 寒风中的细雨
基于上面二路归并的代码, 分享另个运用该归并模板的例子(找最邻近点对)
code.zip (7.29 KB)
2017-04-23 23:44
寒风中的细雨
Rank: 17Rank: 17Rank: 17Rank: 17Rank: 17
等 级:贵宾
威 望:66
帖 子:1710
专家分:8645
注 册:2009-9-15
收藏
得分:0 
方便浏览代码也贴一份
程序代码:
/******************************************************************************

 *\file closest_pair.h

 *\brief 二维平面上求给出的n个点中 找出邻近距离最小的点对

 *\date 2017/04/21

 *****************************************************************************/
#ifndef __CLOSEST_PAIR_H_2017_04_21__
#define    __CLOSEST_PAIR_H_2017_04_21__

#ifdef __cplusplus
extern "C"{
#endif


#define MAX_POINTS    (100)    ///< 最大支持的点的输入

/**

 *\brief 二维坐标点的结构

 */
typedef struct point_st{
    
    double    x;    ///< 坐标x
    double  y;    ///< 坐标y
}point_st;

/**

 *\brief 邻近点对结构

 */
typedef struct closest_pair_st{
    
    point_st p1;    ///< 第一个点
    point_st p2;    ///< 第二个点
    double      d;        ///< 两点间的距离
}closest_pair_st;

/**

 *\brief 点的表结构,按照x或y轴进行排序时使用

 */
typedef struct ptables_st{
    
    unsigned int    idx;    ///< 点在点的集合中位置
    double            xy;        ///< x轴 或 y轴的坐标
}ptables_st;

/**

 *\brief 获取最邻近的点对

 *\param[in] plist 待处理的点信息

 *\param[in] pnum 待处理的点数量

 *\param[out] pair 获取得到的结果

 *\retval 1 成功

 *\retval 0 失败

 */
int get_closest_pair(point_st *plist, unsigned int pnum, closest_pair_st *pair);

#ifdef __cplusplus
}
#endif

#endif//__CLOSEST_PAIR_H_2017_04_21__

程序代码:
/******************************************************************************

 *\file closest_pair.cc

 *\brief 二维平面上求给出的n个点中 找出邻近距离最小的点对

 *\date 2017/04/21

 *****************************************************************************/

#include "closest_pair.h"
#include "merge_sort.h"
#include <stdio.h>
#include <stdlib.h> 
#include <string.h>
#include <assert.h>
#include <math.h>
#include <errno.h>

static ptables_st x_ptables[MAX_POINTS];    // x轴排序列表
static ptables_st y_ptables[MAX_POINTS];    // y轴排序列表
static unsigned int s_spnum;
static ptables_st s_ptables[MAX_POINTS];    // 与垂直线相距特定距离点的列表

/**

 *\brief 归并排序中 设置merge_array的初始值

 *\param[in] len 待初始化的数据规模

 *\param[in] disoder_ary 等待排序的数据

 *\param[in] merge_ary 初始化的对象

 *\retval 1 初始化成功

 *\retval 0 初始化失败

 */
int set_fun(unsigned int len, void *disoder_ary, void **merge_ary)
{
    unsigned int i = 0;
    ptables_st *ary1 = NULL, **ary2 = NULL;
    
    assert((void**)0 != disoder_ary);
    assert((void**)0 != merge_ary);
    
    ary1 = (ptables_st *)disoder_ary;
    ary2 = (ptables_st **)merge_ary;
    
    for (i = 0; i < len; ++i){
        
        ary2[i] = &ary1[i];
    }
    
    return 1;
}

/**

 *\brief 归并排序中 两个元素对比函数

 *\param[in] cmp1 对比元素1

 *\param[in] cmp2 对比元素2

 *\retval 1 cmp1 > cmp2

 *\retval 0 cmp1 = cmp2

 *\retval -1 cmp1 < cmp2

 */
int cmp_fun(void *cmp1, void *cmp2)
{
    ptables_st *int_cmp1 = NULL;
    ptables_st *int_cmp2 = NULL;

    assert(NULL != cmp1);
    assert(NULL != cmp2);
    
    int_cmp1 = (ptables_st*)cmp1;
    int_cmp2 = (ptables_st*)cmp2;
    if (int_cmp1->xy > int_cmp2->xy){
        
        return 1;
    }else if (int_cmp1->xy == int_cmp2->xy){
        
        return 0;
    }
    
    return -1;
}

/**

 *\brief 归并排序中 赋值操作

 *\param[in] lopr 被赋值的 等号 左边的数

 *\param[in] ropr 赋值的 等号 右边的数

 *\retval 1 赋值成功

 *\retval 0 赋值失败 

 */
int agn_fun(void **lopr, void *ropr)
{
    ptables_st **int_lopr = NULL;
    ptables_st *int_ropr = NULL;
    
    assert((void**)0 != lopr);
    assert(NULL != ropr);
    
    int_lopr = (ptables_st **)lopr;
    int_ropr = (ptables_st *)ropr;
    *int_lopr = int_ropr;
    
    return 1;
}

/**

 *\brief 归并排序中 获取排序结果

 *\param[in] len 获取结果的数据规模 

 *\param[in,out] res_ary 等待排序的数据

 *\param[in] merge_ary 归并排序后的结果

 *\retval 1 获取结果成功

 *\retval 0 获取结果失败

 */
int get_res_fun(unsigned int len, void *res_ary, void **merge_ary)
{
    ptables_st *buf = NULL, **ary = (ptables_st**)0, *res = NULL;
    unsigned int i = 0;
    
    assert(0 <= len);
    assert(NULL != res_ary);
    assert((void**)0 != merge_ary);
    
    buf = (ptables_st*) malloc (len * sizeof(ptables_st)); // 这里需要开辟空间 merge_ary,指向的内存地址就是res_ary的元素地址
    if (NULL == buf){
        
        printf("malloc failed, errno(%d)\n", errno);
        return 0;
    }
    ary = (ptables_st **)merge_ary;
    res = (ptables_st *)res_ary;
    
    for (i = 0; i < len; ++i){
        
        memcpy(&buf[i], ary[i], sizeof(ptables_st));    // 取指针指向的内容
    }
    
    memcpy(res, buf, len * sizeof(ptables_st));
    
    free(buf);
    buf = NULL;

    return 1;
}
    
/**

 *\brief 获取两点间的距离

 *\brief[in] plist 点的列表

 *\param[in] i 第一个点在点的列表中下标值

 *\param[in] j 第二个点在点的列表中下标值

 *\retval 2点间的距离值

 */
static double __get_2points_dist(point_st *plist, unsigned int i, unsigned int j)
{
    double x, y;
    
    x = pow(plist[i].x - plist[j].x, 2.0);
    y = pow(plist[i].y - plist[j].y, 2.0);
    
    return sqrt(x + y);
}

/**

 *\brief 递归处理各个分支

 *\param[in] plist 存放所有点列表

 *\param[in] pnum plist列表中点的数量

 *\param[in] beg 待处理点的起始下标

 *\param[in] num 待处理点的数量 从beg下标开始算起

 *\param[out] pair 输出邻近的点对

 *\retval 1 成功

 *\retval 0 失败

 */
static int __do_closest_pair(point_st *plist, 
                             unsigned int pnum,
                             unsigned int beg, 
                             unsigned int num, 
                             closest_pair_st *pair)
{
    unsigned int i = 0, j = 0;
    closest_pair_st l_pair, r_pair, min_pair;
    
    if (num <= 3){
        
        pair->p1.x = plist[beg].x;
        pair->p1.y = plist[beg].y;
        pair->p2.x = plist[beg+1].x;
        pair->p2.y = plist[beg+1].y;
        pair->d = __get_2points_dist(plist, beg, beg + 1);
        
        // 直接计算两点间的距离
        for (i = 0; i < num; ++i){
            
            for (j = i + 1; j < num; ++j){
                
                if (pair->d > __get_2points_dist(plist, beg + i, beg + j)){
                    
                    pair->p1.x = plist[beg+i].x;
                    pair->p1.y = plist[beg+i].y;
                    pair->p2.x = plist[beg+j].x;
                    pair->p2.y = plist[beg+j].y;
                    pair->d = __get_2points_dist(plist, beg + i, beg + j);                    
                }
            }
        }
        
        return 1;
    }
    
    // 拆分成[1, num/2] 和 [num/2 + 1, num]
    __do_closest_pair(plist, pnum, beg, num/2, &l_pair);
    __do_closest_pair(plist, pnum, beg + num/2, num - num/2, &r_pair);
    if (l_pair.d < r_pair.d){
        
        memcpy(&min_pair, &l_pair, sizeof(closest_pair_st));
    }else{
        
        memcpy(&min_pair, &r_pair, sizeof(closest_pair_st));
    }
    
    // 计算两点一点落在左半边 一点落在右半边的情况, 统计所有与垂直直线 x = plist[beg + num/2].x 相距 min_pair.d 的距离的点
    for (i = 0, s_spnum = 0; i < pnum ; ++i){
        
        double dis = fabs(plist[beg + num/2].x - plist[y_ptables[i].idx].x);
        if (min_pair.d > dis){
            
            s_ptables[s_spnum].idx = y_ptables[i].idx;
            s_ptables[s_spnum].xy = y_ptables[i].xy;
            ++s_spnum;
        }
    }
    
    if (s_spnum < 2){
    
        memcpy(pair, &min_pair, sizeof(closest_pair_st));
        return 1;
    }
    
    pair->p1.x = plist[s_ptables[0].idx].x;
    pair->p1.y = plist[s_ptables[0].idx].y;
    pair->p2.x = plist[s_ptables[1].idx].x;
    pair->p2.y = plist[s_ptables[1].idx].y;
    pair->d = __get_2points_dist(plist, s_ptables[0].idx, s_ptables[1].idx);
    for (i = 0; i < s_spnum; ++i){
        
        for (j = i+1; j <= i + 8 && j < s_spnum; ++j){
            
            if (pair->d > __get_2points_dist(plist, s_ptables[i].idx, s_ptables[j].idx)){
                
                pair->p1.x = plist[s_ptables[i].idx].x;
                pair->p1.y = plist[s_ptables[i].idx].y;
                pair->p2.x = plist[s_ptables[j].idx].x;
                pair->p2.y = plist[s_ptables[j].idx].y;
                pair->d = __get_2points_dist(plist, s_ptables[i].idx, s_ptables[j].idx);                
            }        
        }
    }
    
    if (min_pair.d < pair->d){
        
        memcpy(pair, &min_pair, sizeof(closest_pair_st));
    }
    
    return 1;
}

/**

 *\brief 获取最邻近的点对

 *\param[in] plist 待处理的点信息

 *\param[in] pnum 待处理的点数量

 *\param[out] pair 获取得到的结果

 *\retval 1 成功

 *\retval 0 失败

 */
int get_closest_pair(point_st *plist, unsigned int pnum, closest_pair_st *pair)
{
    unsigned int i = 0;
    
    
    assert(NULL != plist);
    assert(NULL != pair);
    assert(MAX_POINTS >= pnum);
    
    // 1. 将plist的点 按照x轴 和 y轴排序(归并排序) 得到两张表
    for (i = 0; i < pnum; ++i){
        
        x_ptables[i].xy = plist[i].x;
        y_ptables[i].xy = plist[i].y;
        x_ptables[i].idx = i;
        y_ptables[i].idx = i;
    }
    // 调用归并排序
    merge_init(pnum, (void *)x_ptables, set_fun, cmp_fun, agn_fun);
    merge_sort(pnum, (void *)x_ptables, get_res_fun);
    merge_destory();
    merge_init(pnum, (void *)y_ptables, set_fun, cmp_fun, agn_fun);
    merge_sort(pnum, (void *)y_ptables, get_res_fun);
    merge_destory();    
        
    // 2.查找最小临近点对
    __do_closest_pair(plist, pnum, 0, pnum, pair);
    
    return 1;
}

程序代码:
/******************************************************************************

 *\file main.cc

 *\brief 二维平面上求给出的n个点中 找出邻近距离最小的点对

 *\date 2017/04/21

 *****************************************************************************/

#include "closest_pair.h"
#include <stdio.h>
#include <assert.h>


static unsigned int s_points_num;        ///< 点的数量
static point_st s_points[MAX_POINTS];    ///< 点的列表


/**

 *\brief 捕获终端输入信息

 *\retval 1 成功

 *\retval 0 失败

 */
static int get_input(void)
{
    unsigned int i = 0;
    
    printf("输入点的数量:");
    scanf("%u", &s_points_num);
    
    assert(MAX_POINTS >= s_points_num);
    
    printf("一行一个点 例如:4,5   其中4为x轴坐标 5为y轴坐标\n");
    for (i = 0; i < s_points_num; ++i){
        
        scanf("%lf,%lf", &s_points[i].x, &s_points[i].y);
    }
    
    return 0;
}

int main(void)
{
    closest_pair_st pair;
    
    get_input();
    
    if (get_closest_pair(s_points, s_points_num, &pair)){
    
        // 输出结果
        printf("(%lf, %lf)<->(%lf, %lf) dis[%lf]\n", pair.p1.x, pair.p1.y, pair.p2.x, pair.p2.y, pair.d);
    }
    
    return 0;
}

2017-04-23 23:47
快速回复:分享一份归并排序代码,欢迎测试改进
数据加载中...
 
   



关于我们 | 广告合作 | 编程中国 | 清除Cookies | TOP | 手机版

编程中国 版权所有,并保留所有权利。
Powered by Discuz, Processed in 0.026708 second(s), 9 queries.
Copyright©2004-2024, BCCN.NET, All Rights Reserved