如何对数组进行排序但保留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
放在具有索引 3
的 5
之前。但是,使用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;
或者,可能更易读和更迂腐(因为没有记录 a
和 b
保证是不同的):
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中重复元素的位置?的主要内容,如果未能解决你的问题,请参考以下文章