如何对数组进行排序但保留C中重复元素的位置?

Posted

技术标签:

【中文标题】如何对数组进行排序但保留C中重复元素的位置?【英文标题】:How to Sort Array But Keep The Position of Duplicate Element in C? 【发布时间】:2018-01-21 12:22:29 【问题描述】:

所以,实际上我需要的是在排序后保留旧数组的索引。例如,如果我输入[2,4,1,5,7,9,6],则输出为[2,0,1,3,6,4,5]。我已经使用了qsort,如果没有重复元素,它会很好地工作。

如果有重复的元素,有时第一个重复的元素放在最后。比如输入是[5,4,6,5,2,1,3],我想输出的是[5,4,6,1,0,3,2]。所以,5 具有索引 0 放在具有索引 35 之前。但是,使用qsort 有时会输出[5,4,6,1,3,0,2]

你能帮我解决这个问题吗?或者我应该创建自己的排序功能?你能帮我创建它吗?

这是我的代码:

#include <stdlib.h>

int* sortidx(double *X,int n)

    int *idx,i,j;

    int cmp(const void *a,const void *b)
    
        return X[*(int*)a]>=X[*(int*)b]?1:-1;
    

    idx=(int*)calloc(n,sizeof(int));

    for(i=0;i<n;i++)
    
        idx[i]=i;
    

    qsort(idx,n,sizeof(int),cmp);

    return idx;

【问题讨论】:

您似乎需要所谓的“稳定”排序算法。在这里查看en.wikipedia.org/wiki/Sorting_algorithm#Stability的含义。然后从那些描述为“稳定”的算法中选择一种算法,你就应该设置好了。 您正在寻找的称为稳定排序。谷歌搜索“stable qsort c”会带来一些点击;我建议你看看这些。 顺便说一句,您使用的是 GCC 扩展的嵌套函数。 【参考方案1】:

您需要的是stable sorting algorithm。您可以在 C 中使用stabilize qsort,但这需要额外的工作。在 C++ 中存在std::stable_sort

如果您需要坚持使用 C,那么您应该实现自己的稳定排序。这是list的稳定排序算法:

B
Block sort
Bubble sort
Bucket sort
C
Cascade merge sort
Cocktail shaker sort
Counting sort
Cubesort
G
Gnome sort
I
Insertion sort
L
Library sort
M
Merge sort
O
Odd–even sort
Oscillating merge sort
P
Pigeonhole sort
Proxmap sort
R
Radix sort
T
Timsort

【讨论】:

正如您对所链接问题的回答所说,您可以通过使用原始索引打破平局来稳定qsort @interjay 我明白了,谢谢,答案更新了,你现在怎么看? =)【参考方案2】:

如果一个元素的值更大或者值相等且其索引更大,则您希望一个元素被认为大于另一个元素。 (这就是稳定排序算法背后的理念。)

在这种情况下,您知道被比较元素的索引,因此您可以轻松地将其添加到您的比较标准中:

int cmp(const void *a, const void *b)

    return X[*(int*)a] > X[*(int*)b] ||
           (X[*(int*)a] == X[*(int*)b] && *(int*)a > *(int*)b)
           ?1:-1;

或者,可能更易读和更迂腐(因为没有记录 ab 保证是不同的):

int cmp(const void *a, const void *b)

    int idxa = *(const int*)a, idxb = *(const int*)b;
    if (X[idxa] > X[idxb]) return 1;
    if (X[idxa] < X[idxb]) return -1;
    return idxa - idxb;

使用引用参数X 的嵌套函数是gcc 扩展,可能不适用于其他编译器。标准 C 库的 Gnu 实现还包含函数 qsort_r,可用于将 X 传递给比较例程,但编写函数的更可移植的方法是使用指针数组而不是索引数组:

int idxcmp(const void *a,const void *b)

    double *ap = *(double *const*)a, *bp = *(double *const*)b;
    if (*ap > *bp) return 1;
    if (*ap < *bp) return -1;
    return ap - bp; 


double** sortidx(double *X, size_t n)

    double **idx = calloc(n, sizeof(double*));
    for (size_t i=0; i<n; ++i) idx[i] = X + i;
    qsort(idx, n, sizeof(idx[0]), idxcmp);
    return idx;

(如果真的要返回索引,可以在返回前将指针转换为索引。)

【讨论】:

不错。我也想过比较索引,但我不知道把它放在哪里最好。我会试试看。非常感谢。 ^^

以上是关于如何对数组进行排序但保留C中重复元素的位置?的主要内容,如果未能解决你的问题,请参考以下文章

如何去掉一个数组的重复元素:数组去重

mpi生成随机数组并进行排序

如何按轴对numpy数组进行排序并保留行[重复]

php数组的重复值如何过滤掉

我如何按类属性对C++向量数组进行排序[重复]

python如何删除list里重复的元素