使用多个排序条件对数组进行排序 (QuickSort)
Posted
技术标签:
【中文标题】使用多个排序条件对数组进行排序 (QuickSort)【英文标题】:Sorting an array using multiple sort criteria (QuickSort) 【发布时间】:2012-11-02 15:16:25 【问题描述】:我试图找出如何(使用快速排序算法)按 2 个标准对结构数组进行排序。例如说我有一个结构:
struct employee
char gender[12];
char name[12];
int id;
;
假设我的输入是:
struct employee arr[3]=
"male","Matt",1234,
"female","Jessica",2345,
"male","Josh",1235
;
我想先按性别对元素进行排序,然后按升序对 ID 进行排序。一个例子是让所有男性首先按顺序打印他们的 ID,然后所有女性都打印他们的 ID。我试图在不使用 qsort 函数的情况下执行此操作,但我一点也不知道如何检查。这是我的排序功能:
void quicksort(struct employee *arr, int left, int right)
int pivot, l, r, temp;
if(left < right)
p = left;
l = left;
r = right;
while(l < r)
while(arr[l].id <= arr[p].id && l <= right)
l++;
while(arr[r].id > arr[p].id && r >= left)
r--;
if(l < r)
temp = arr[l].id;
arr[l].id = arr[r].id;
arr[r].id = temp;
temp = arr[r].id;
arr[r].id = arr[p].id;
arr[p].id = temp;
quicksort(arr, left, r-1);
quicksort(arr, r+1, right);
有什么建议吗?我在想我可以使用 strcmp,但我不知道在函数中包含它的位置。
【问题讨论】:
【参考方案1】:只需使用内置的qsort
,并传递给它一个比较器函数,它首先比较性别,并且只有在第一次比较“tie”的情况下才查询ID号。
【讨论】:
谢谢,我确实意识到了这一点,但我想看看如果它是硬编码的,而不是使用 qsort 会如何工作【参考方案2】:我认为您应该首先按性别对数组进行排序,男性一个,女性一个。然后使用快速排序函数在这两个数组中进行排序。
您可以使用strcmp将原始数组排序为两个数组:一个为男性,一个为女性。
【讨论】:
可以像这样在两遍中进行排序 - 但是当/如果你这样做时,使用稳定的排序至关重要(在平局的情况下保持原始顺序)。快速排序,至少与通常为数组实现的一样,是不稳定的。【参考方案3】:这并不难。您只需要一个函数(或看到您想要“硬编码”的代码块)来比较您的结构。在您提供的示例代码中,您使用arr[l].id <= arr[p].id
比较当前对象。那就是您只考虑 id 来确定您的元素适合的位置。此时您只需要使用其他字段进行比较。使用函数会更整洁(我在之前的问题中给了你这样的函数)。
您也只是在交换时移动 id 字段 - 在您的数据项中保持名称和性别不变。你应该移动整个结构。
【讨论】:
啊,感谢您发现我没有注意到。当我尝试切换 arr[l]=arr[r] 时,出现语法错误。【参考方案4】:int compare_employee (struct employee * a, struct employee * b)
int diff = strcmp(a->gender, b->gender);
if (diff) // if gender different
return -diff; // sort descending, please double check this and reverse in case I am wrong
return a->id - b->id; // else sort by id
如果a < b
输出负数,如果a > b
输出正数,如果相等则输出零。
在您自己的快速排序中或作为qsort
比较器使用它。
【讨论】:
【参考方案5】:你当然可以内联比较函数,以及一个交换器。下面的代码非常基本,并且依赖于有效的指针,但你会明白的。我还冒昧地减少了您的快速排序,修复了沿途的问题(我希望如此)。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// employee record
struct employee
char gender[12];
char name[12];
int id;
;
// swap employee records
void swap_employee(struct employee *left, struct employee *right)
struct employee tmp = *right;
*right = *left;
*left = tmp;
// compare employee records
int compare_employee(const struct employee* left,
const struct employee* right)
int gender = strcmp(left->gender, right->gender);
return (gender ? gender : (left->id - right->id));
// quicksort for employees
static void quicksort_(struct employee *arr, int left, int right)
struct employee p = arr[(left+right)/2]; // as good as any
int l = left, r = right; // movable indicies
while (l <= r)
while (compare_employee(arr+l, &p) < 0)
++l;
while (compare_employee(arr+r, &p) > 0)
--r;
if (l <= r)
swap_employee(arr+l, arr+r);
++l; --r;
if (left < r)
quicksort_(arr, left, r);
if (l < right)
quicksort_(arr, l, right);
// exposed API
void quicksort(struct employee *arr, int count)
if (arr && (count>0))
quicksort_(arr, 0, count-1);
/* sample usage */
int main(int argc, char *argv[])
struct employee arr[]=
"male","Matt",1234,
"female","Jessica",2345,
"male","Josh",1235,
"female","Betsy",2344,
"male","Roger",1233
;
quicksort(arr, sizeof(arr)/sizeof(arr[0]));
for (int i=0;i<sizeof(arr)/sizeof(arr[0]);++i)
printf("%s, %s, %d\n", arr[i].gender,arr[i].name, arr[i].id);
return EXIT_SUCCESS;
结果
female, Betsy, 2344
female, Jessica, 2345
male, Roger, 1233
male, Matt, 1234
male, Josh, 1235
【讨论】:
以上是关于使用多个排序条件对数组进行排序 (QuickSort)的主要内容,如果未能解决你的问题,请参考以下文章