如何按特定单元格快速排序二维数组?
Posted
技术标签:
【中文标题】如何按特定单元格快速排序二维数组?【英文标题】:How can I quicksort a two dimension array by a specific cell? 【发布时间】:2012-12-24 14:37:08 【问题描述】:我有一个二维数组,我想用 C++ 中给定的 qsort() 函数对其进行快速排序:
unsigned work[N][3];
我想按第三个索引对“工作”数组进行排序...所以如果work[i]
在work[j]
之前,如果work[i][2]>work[j][2]
。
我知道我需要使用一个函数来比较它,但我不知道该怎么做。
编辑: 如果我会执行以下操作,会有所帮助吗:
unsigned work[3][N];
qsort(work[2], N, sizeof(unsigned), compare);
比较如下:
int compare(const void* a, const void* b)
return(*(unsigned*)a-*(unsigned*)b);
?
【问题讨论】:
请澄清:这是 C 还是 C++?如果您使用 C++,解决方案很简单:不要使用 C 数组,而是使用 C++ 数据容器,并且使用std::sort()
而不是 qsort()
。 std::sort()
也更快...
我真的是一个编程新手,我正在尝试使用 C++,所以如果你能给我一些提到的 C++ 数据容器的例子,我会照顾它们。
“如果我执行以下操作,会有帮助吗?” - 不,不会。你读过答案吗?
“我正在尝试使用 C++” - 那么为什么你的问题又被转为 C?现在一劳永逸,你要使用C还是C++(请不要说C/C++,那比当前的混乱疯狂)。
@DevSolar 您是否只是通过将问题重新标记为完全不同的语言来完全改变问题(与 OP 的 cmets 相反)?
【参考方案1】:
嗯,简短的回答是根本不使用std::qsort
,而是使用std::sort
。但不幸的是后者不起作用,因为unsigned int[3]
是不可分配的。所以这是最简单的std::qsort
解决方案。
首先我们定义一个自定义比较器函数:
// return -1 if a before b, 1 if after, 0 if equal
int compare(const void *a, const void *b)
const unsigned int *arg1 = reinterpret_cast<const unsigned int*>(a);
const unsigned int *arg2 = reinterpret_cast<const unsigned int*>(b);
if(arg1[2] > arg2[2])
return -1;
if(arg1[2] < arg2[2])
return 1;
return 0;
然后我们用它来对数组进行排序。请记住,work
是一个数组数组,因此work[0]
是一个由 3 个unsigned int
s 组成的数组,不涉及任何指针间接寻址。所以非常适合被std::qsort
排序:
std::qsort(work, sizeof(work)/sizeof(work[0]), sizeof(work[0]), compare);
顺便说一句,第三个元素以2
为索引,因为在 C++(和许多其他编程语言)中我们通常从0
开始计数。
编辑:尽管如此,最好的解决方案确实是删除这个数组数组并使用更适合 C++ 的东西,比如 std::array<unsigned int,3>
s 的 std::vector
(或任何其他数据结构)更符合实际情况):
typedef std::array<unsigned int,3> uint3;
std::vector<uint3> work(N);
然后可以用一个简单的排序:
std::sort(std::begin(work), std::end(work),
[](const uint3 &a, const uint3 &b) return a[2] > b[2]; );
或者,如果您没有 C++11(尽管在这种情况下,您也没有 std::array
并且需要开始考虑一个合理的数据结构,而不仅仅是一个 3 数组):
struct compare
bool operator()(const uint3 &a, const uint3 &b) const
return a[2] > b[2];
;
std::sort(work.begin(), work.end(), compare());
除了更清晰的代码之外,您还很可能会在std::sort
上比std::qsort
稍微提高性能。
【讨论】:
下面的呢:unsigned work[3][N]; qsort(work[3], N, sizeof(unsigned), compare);
@nábob 不,那是错误的。第一个参数是数组的开头,它只是work
,衰减到一个指针,work[3]
将是第三个元素。第二个参数是元素的数量,即数组的大小(sizeof(work)
)除以一个元素的大小(sizeof(work[0])
)(好吧,最后确实是N
)。第三个参数是单个元素的大小,即sizeof(work[0])
(实际上是3*sizeof(unsigned int)
)。如果您不知道如何调用该函数(在这种情况下您不会发布问题),为什么还要为该函数提供自己的参数?【参考方案2】:
是的,你可以qsort()
这个。 qsort()
通过获取所需的线性“东西”块,将其划分为统一大小的块,您指定大小(以字节为单位),然后为您提供基础每个块分区的地址进行比较。
首先,确定您需要的尺寸。很明显,您要排序的“事物”是数组 rows 三个元素宽。其次,编写一个比较器,它可以接受两个诸如指针之类的基地址,在我们的例子中,一个简单的指针就可以工作,因为它很好地剥离了外部数组维度。最后,实际比较将是每个指针p
的三个元素深度(准确地说是p[2]
):
让我们充实代码:
#include <stdlib.h>
#include <stdio.h>
#include <memory.h>
#include <time.h>
static const size_t ROWSIZE = 3;
static void print_array(int rows, int ar[rows][ROWSIZE])
int i,j;
for (i=0;i<rows;++i)
for (j=0; j<ROWSIZE; printf("%d ", ar[i][j++]));
printf("\n");
printf("\n");
// compare function
static int compare_row(const void* left, const void* right)
const int *ileft = left, *iright = right;
return ileft[ROWSIZE-1] - iright[ROWSIZE-1];
int main()
int ar[10][ROWSIZE] = 0, i;
// fill with random junk from 10 to 99
srand((unsigned)time(0));
for (i=0;i<ROWSIZE * sizeof(ar)/sizeof(ar[0]); ++i)
ar[i/ROWSIZE][i%ROWSIZE] = 10 + (rand() % 90);
// print prior to sort.
print_array(sizeof(ar)/sizeof(ar[0]), ar);
// send to qsort
qsort(ar, sizeof(ar)/sizeof(ar[0]), sizeof(ar[0]), compare_row);
// print again after sort.
print_array(sizeof(ar)/sizeof(ar[0]), ar);
return EXIT_SUCCESS;
样本输出
50 14 23
69 81 93
30 72 18
26 49 29
51 87 58
18 74 40
26 61 26
43 80 27
27 61 34
13 66 89
30 72 18
50 14 23
26 61 26
43 80 27
26 49 29
27 61 34
18 74 40
51 87 58
13 66 89
69 81 93
【讨论】:
如果我的比较器函数体是:const int (*ileft)[ROWSIZE] = (const int (*)[ROWSIZE])left, (*iright)[ROWSIZE] = (const int (*)[ROWSIZE])right; return (*ileft)[ROWSIZE-1] - (*iright)[ROWSIZE-1];
?以上是关于如何按特定单元格快速排序二维数组?的主要内容,如果未能解决你的问题,请参考以下文章
LeetCode 417. 太平洋大西洋水流问题(多源bfs) / 905. 按奇偶排序数组 / 427. 建立四叉树(dfs+二维前缀和)