簡體   English   中英

矩陣排序合並排序 C

[英]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 的每個指針都是指向一維數組(行)的指針

所以每個ab都將是一個指向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) 。試試吧。為ab選擇任意兩個值並計算結果。在升序情況下, a小於b ,您return 0 - 1; (或-1 ),例如表示ab之前排序)

那么對比 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,您可以將比較指針ab轉換為int *並添加兩個。 這是等效的,但不反映正式演員表。 (您也可以將整個演員表括在括號中並使用[2] )。

在這種情況下,演員表看起來要簡單得多,但實際發生的事情可能不太明顯。 我將留給您嘗試將完整程序中的*(int (*)[3])替換為(int *) (這將避免將在評論中進行的曠日持久的討論)

仔細查看並思考“傳遞的是什么類型的指針?” 以及為什么在比較 function 中使用兩次比較的結果而不僅僅是減法作為返回以避免溢出。 如果您還有其他問題,請告訴我。

腳注:

1.) C11 標准 - 6.3.2.1 其他操作數 - 左值、arrays 和 function 指示符(p3)除非它是sizeof運算符、 _Alignof字符串運算符的操作數或一元運算符'&'用於初始化數組,類型為“類型數組”的表達式被轉換為類型為“類型指針”的表達式,該類型指向數組 object 的初始元素並且不是左值。

以大衛 C 為基礎。 Rankin 的回答,你必須考慮另一個問題:你希望獲得的精確排序順序是什么?

從您提供的示例中可以推斷出二維數組的第三列是主鍵。 然而,這還不足以完全指定排序順序。 以下是三種可能性:

  1. 第三列中具有相同元素的行的順序無關緊要。 在這種情況下,可能有許多不同的輸出,都是正確的。
  2. 具有相同元素的行的順序應與原始二維數組中的相同。 為此,您需要一個穩定的排序算法,例如mergesort ,但qsort通常結合快速排序和其他用於病理情況的方法來實現,使其不穩定,因此不適合您的目的。
  3. 第 3 列中具有相同元素的行的順序應根據第二列中的值確定,如果這些值也相同,則應根據第一列中的值確定。 提供的示例與此方法一致。 (從您對 Jonathan Leffler 評論的回復來看,這應該是您的偏好)。

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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM