[英]Matrix Sorting mergesort C
我有這個問題,我必須對矩陣進行排序,例如:
0 0 4
1 0 3
0 1 4
1 1 5
0 2 3
1 2 4
至:
1 0 3
0 2 3
0 0 4
0 1 4
1 2 4
1 1 5
所以行保持不變,每列從小到大,如示例所示。 矩陣總是有 3 列和 x 行。
我已經嘗試過插入排序,盡管工作它效率不高,並且考慮到實際應用程序中的行數,運行起來需要很多時間。
我將提供一個我假裝的小代碼:
#include <stdio.h>
int main() {
int abc[6][3] = {
{ 0, 0, 4 },
{ 1, 0, 3 },
{ 0, 1, 4 },
{ 1, 1, 5 },
{ 0, 2, 3 },
{ 1, 2, 4 },
};
//
//sort
//
for (int i = 0; i < 6; ++i) {
printf("%d %d %d\n", abc[i][0], abc[i][1], abc[i][2]);
}
return 0;
}
我想嘗試合並排序和快速排序,但感謝任何幫助。
先感謝您。
您可以通過四種方式之一(兩種形式正確,但都等效1 )來編寫比較 function 。 可怕的qsort
原型int compare (const void *a, const void *b)
只是 C 將指針傳遞給要排序的數組元素的方式。 您的工作只是在比較 function 之前轉換回正確的類型。
真正的問題是“傳遞的是什么類型的指針?
當您回答時,這很容易。 您正在按行對二維數組進行排序。 二維數組實際上是一維 arrays 的數組。 傳遞給 compare 的每個指針都是指向一維數組(行)的指針
所以每個a
和b
都將是一個指向int [3]
數組的指針。 在您的比較 function 中,您需要轉換為指向int [3]
數組的指針,然后取消引用一次以將類型保留為int [3]
,然后根據第三個元素進行比較。 (但是當您訪問您現在的類型int [3]
數組指針轉換也適用於該數組,因此您只需將2
添加到您的指針值並取消引用以通過第三個元素進行比較)。
您可以使用兩個條件測試的結果來避免可能由於簡單地返回b - a
而導致的溢出,如果b
是一個大的負數並且a
很大(或b
是一個大的正數和a
大的負數)將如果結果超出int
的存儲容量,則會發生。 因此,對於升序排序,您可以使用:
return (a > b) - (a < b);
(對於降序排序,只需翻轉比較,例如(a < b) - (a > b)
。試試吧。為a
和b
選擇任意兩個值並計算結果。在升序情況下, a
小於b
,您return 0 - 1;
(或-1
),例如表示a
在b
之前排序)
那么對比 function 是什么樣子的呢? 由於指向int [3]
數組的指針的正式類型是int (*)[3]
,您可以這樣做:
int comp (const void *a, const void *b)
{
int *pa2 = *(int (*)[3])a + 2,
*pb2 = *(int (*)[3])b + 2;
return (*pa2 > *pb2) - (*pa2 < *pb2);
}
或者,如果您想簡單地制作int pa2
而不必擔心在比較中必須取消引用指針,對於第二次正式轉換,您可以將a
的完整轉換括在括號中,然后只需使用(stuff a)[2]
到直接訪問第三個 integer 值——它只會使演員看起來更混亂,例如
int comp (const void *a, const void *b)
{
int pa2 = (*(int (*)[3])a)[2],
pb2 = (*(int (*)[3])b)[2];
return (pa2 > pb2) - (pa2 < pb2);
}
(對你來說最有意義的)
然后按二維數組中每一行的第三個元素進行排序真的很簡單,例如
#include <stdio.h>
#include <stdlib.h>
int comp (const void *a, const void *b)
{
int *pa2 = *(int (*)[3])a + 2,
*pb2 = *(int (*)[3])b + 2;
return (*pa2 > *pb2) - (*pa2 < *pb2);
}
int main() {
int abc[6][3] ={{0,0,4},
{1,0,3},
{0,1,4},
{1,1,5},
{0,2,3},
{1,2,4}};
qsort (abc, 6, sizeof *abc, comp);
for (int i = 0; i < 6; ++i)
printf(" %2d %2d %2d\n", abc[i][0], abc[i][1], abc[i][2]);
}
示例使用/輸出
$ ./bin/qsort2d+2
1 0 3
0 2 3
0 0 4
0 1 4
1 2 4
1 1 5
現在編寫比較 function 轉換的最后兩種等效方法依賴於數組/指針轉換的連續應用,並理解指向數組的指針和數組本身都將指向相同的地址(但形式上是不同的類型)正式地你有int (*)[3]
但既然您知道您只需要該地址之后的第二個 integer,您可以將比較指針a
和b
轉換為int *
並添加兩個。 這是等效的,但不反映正式演員表。 (您也可以將整個演員表括在括號中並使用[2]
)。
在這種情況下,演員表看起來要簡單得多,但實際發生的事情可能不太明顯。 我將留給您嘗試將完整程序中的*(int (*)[3])
替換為(int *)
。 (這將避免將在評論中進行的曠日持久的討論)
仔細查看並思考“傳遞的是什么類型的指針?” 以及為什么在比較 function 中使用兩次比較的結果而不僅僅是減法作為返回以避免溢出。 如果您還有其他問題,請告訴我。
腳注:
1.) C11 標准 - 6.3.2.1 其他操作數 - 左值、arrays 和 function 指示符(p3)除非它是sizeof
運算符、 _Alignof
或字符串運算符的操作數或一元運算符'&'
用於初始化數組,類型為“類型數組”的表達式被轉換為類型為“類型指針”的表達式,該類型指向數組 object 的初始元素並且不是左值。
以大衛 C 為基礎。 Rankin 的回答,你必須考慮另一個問題:你希望獲得的精確排序順序是什么?
從您提供的示例中可以推斷出二維數組的第三列是主鍵。 然而,這還不足以完全指定排序順序。 以下是三種可能性:
mergesort
,但qsort
通常結合快速排序和其他用於病理情況的方法來實現,使其不穩定,因此不適合您的目的。 qsort()
適用於方法 1 和 3,但不適用於方法 2。
這是方法1的更簡單的比較function:
int comp2(const void *a, const void *b) {
const int *pa = a;
const int *pb = b;
return (pa[2] > pb[2]) - (pa[2] < pb[2]);
}
comp2
可用於方法 2,但您必須調用mergesort()
而不是qsort()
:
mergesort(abc, sizeof abc / sizeof *abc, sizeof *abc, comp2);
這是方法3的比較function:
int comp_full(const void *a, const void *b) {
const int *pa = a;
const int *pb = b;
if (pa[2] != pb[2])
return (pa[2] > pb[2]) - (pa[2] < pb[2]);
if (pa[1] != pb[1])
return (pa[1] > pb[1]) - (pa[1] < pb[1]);
else
return (pa[0] > pb[0]) - (pa[0] < pb[0]);
}
這是一個針對 BSD 系統的測試程序:
#include <stdio.h>
#include <stdlib.h>
int comp_full(const void *a, const void *b) {
const int *pa = a;
const int *pb = b;
if (pa[2] != pb[2])
return (pa[2] > pb[2]) - (pa[2] < pb[2]);
if (pa[1] != pb[1])
return (pa[1] > pb[1]) - (pa[1] < pb[1]);
else
return (pa[0] > pb[0]) - (pa[0] < pb[0]);
}
int comp2(const void *a, const void *b) {
const int *pa = a;
const int *pb = b;
return (pa[2] > pb[2]) - (pa[2] < pb[2]);
}
int use_stable_sort = 0;
int main() {
int abc[][3] = {
{ 0, 0, 4 },
{ 1, 0, 3 },
{ 0, 1, 4 },
{ 1, 1, 5 },
{ 0, 2, 3 },
{ 1, 2, 4 },
};
if (use_stable_sort)
mergesort(abc, sizeof abc / sizeof *abc, sizeof *abc, comp2);
else
qsort(abc, sizeof abc / sizeof *abc, sizeof *abc, comp_full);
for (int i = 0, n = sizeof abc / sizeof *abc; i < n; ++i)
printf("%d %d %d\n", abc[i][0], abc[i][1], abc[i][2]);
return 0;
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.