質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

87.79%

構造体リストのメンバを比べてを昇順、降順ならびかえる

受付中

回答 2

投稿

  • 評価
  • クリップ 0
  • VIEW 348

score 1

構造体のリストを並び替えたい。リストを並び替えるプログラムを作ったが、構造体メンバごとに昇順、降順に並び替えたい。

2:ソートを押下

名前 住所

昇順、降順

並び替え

といったプログラムにしたいです。
いまのプログラムは住所について並び直しています。
名前について並び直したいときは、もう一つソート関数のコードを書く以外の書き方がわかりません。構造体ポインタのメンバを引数にする?とか可能なのでしょうか?
また、降順についても、わかりやすい書き方がしたいです。

以下ソースコードになります。

#include <stdio.h>  
#include <string.h> 
#include <stdlib.h>  
#define NO_PROBLEM 0
#define ERROR 1

typedef struct student {
    int id;
    char name[10 + 1];
    char address[10 + 1];
    struct student *next;
} PERSON_t;

static PERSON_t *head = NULL;
static PERSON_t *tail = NULL;

int add_person(int id);
int sort_person(void);
void print_person(PERSON_t *p);
PERSON_t * quick_sort(PERSON_t *a);

int main(void)
{
    int number = 0;
    int id = 0;
    while (1) {
        printf("1.追加入力  2.ソート  3.表示  0.終了: ");
        scanf("%d", &number);
        switch (number) {
        case 0:
            return 0;
        case 1:
            if (add_person(++id) == NO_PROBLEM){
                 puts("追加完了");
            }
            break;
        case 2:
                head = quick_sort(head );
                 puts("並べ替え完了");
            break;
        case 3:
            print_person(head);
        }
    }
}



PERSON_t * quick_sort(PERSON_t *a)
{
    PERSON_t *pivot = a;      //初めの文字をpivotとする a = head 基準
    PERSON_t *less = NULL;   //基準より小さい
    PERSON_t *greater = NULL;  //基準より大きい
    PERSON_t *z;
    if (a == NULL || a->next == NULL){ //何もなかったらreturn
        puts("NULL");
        return a;
    }

    puts("1");
    a = a->next; 
    pivot->next = NULL;
    while (a) {
        int diff;
        diff = strcmp(a->address, pivot->address); 
        if (diff < 0){  
             z = a;
             a = a->next;
             z->next = less;
             less = z;
        }
        else if (diff > 0){  
             z = a;
             a = a->next; 
             z->next = greater;
             greater = z;

        }
        else {     
            z = a;
            a = a->next;
            z->next = pivot;
              pivot = z;

        }
    }
    less = quick_sort(less);
    greater = quick_sort(greater);

    if (less == NULL){
         a = pivot;
         printf("基準%s",pivot);
    }
    else {
        for (a = z = less; z && z->next; z = z->next) ;
        z->next = pivot;
    }
    for (z = pivot; z->next; z = z->next) ;
    puts("8");
           z->next = greater;
    return a;
}

int add_person(int id)
{
    PERSON_t *data;
    data = (PERSON_t *)malloc(sizeof(PERSON_t));
    data->id = id;
    printf("ID->%d\n", data->id);
    scanf("%10s", data->name);
    fflush(stdin);
    scanf("%10s", data->address);

    data->next = NULL;
    if (head == NULL) {
         head = data;
         tail = data;
    } else {
        tail->next = data;
        tail = data;
    }
        return NO_PROBLEM;
    }

void print_person(PERSON_t *p)
{
    for (; p; p = p->next){
            printf(" %s", p->name);
         printf(" %s\n", p->address);
    }
    putchar('\n');
}
  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 2

0

diff = strcmp(a->address, pivot->address);

ここでaddressかnameかに分ければいいかと思います。

(元のコードを生かした書き方をします。日本語のところはご自身で適当な名前をつけてください。)

PERSON_t * quick_sort(PERSON_t *a, int (ソート種別));

PERSON_t * quick_sort(PERSON_t *a, int (ソート種別))
{
  char *pPivot; // pivot用ポインタ

(省略)

    puts("1");
    a = a->next; 
    pivot->next = NULL;
    /********追加コード*******/
    if ((ソート種別) == 住所)
    {
      pPivot = pPivot->address;
    }
    else  // if ((ソート種別) == 名前)
    {
      pPivot = pPivot->name;
    }
    /********ここまで(追加コード)*******/
    while (a) {
        int diff;
        /********追加コード*******/
        char *pA;
        if ((ソート種別)==住所)
        {
            pA = pivot->address;
        }
        else // if ((ソート種別) == 名前)
        {
            pA = pivot->name;
        }

        diff = strcmp(pA, pPivot); // diff = strcmp(a->address, pivot->address);から書き換え
        /********ここまで(追加コード)*******/

    (以下略)

こんな感じでaddressとname、どちらかを示す中間ポインタを宣言して使用すればいいのではないでしょうか?

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2021/05/18 01:56

    追加したコード部分を関数にした方がコードの修正漏れなどが減るので、できれば関数化したいところです。

    キャンセル

0

比較関数を渡せばいいでしょう。

#include <stdio.h>  
#include <string.h> 
#include <stdlib.h>  

#define NO_PROBLEM 0

typedef struct student {
    int id;
    char name[10 + 1];
    char address[10 + 1];
    struct student *next;
} PERSON_t;

static PERSON_t *head = NULL;
static PERSON_t *tail = NULL;

int add_person(int id);
void print_person(PERSON_t *p);
PERSON_t * quick_sort(PERSON_t *a, int comp(PERSON_t *, PERSON_t *));
int compare_name(PERSON_t *a, PERSON_t *b);
int compare_address(PERSON_t *a, PERSON_t *b);

int main(void)
{
    int number = 0;
    int id = 0;
    while (1) {
        printf("1.追加入力  2.表示  3.名前でソート  4.住所でソート  0.終了: ");
        scanf("%d", &number);
        switch (number) {
        case 0:
            return 0;
        case 1:
            if (add_person(++id) == NO_PROBLEM)puts("追加完了");
            break;
        case 2:
            print_person(head);
            break;
        case 3:
            head = quick_sort(head, compare_name);
            puts("並べ替え完了");
            break;
        case 4:
            head = quick_sort(head, compare_address);
            puts("並べ替え完了");
            break;
        }
    }
}


PERSON_t * quick_sort(PERSON_t *a, int comp(PERSON_t *, PERSON_t *))
{
    PERSON_t *pivot = a;      //初めの文字をpivotとする a = head 基準
    PERSON_t *less = NULL;    //基準より小さい
    PERSON_t *greater = NULL; //基準より大きい
    PERSON_t *z;
    if (a == NULL || a->next == NULL) return a; //要素数が 0 か 1 の時 

    a = a->next; 
    pivot->next = NULL;
    while (a) {
        z = a;
        a = a->next;
        int diff = comp(z, pivot); 
        if (diff < 0) {
            z->next = less;
            less = z;
        }
        else if (diff > 0) {
            z->next = greater;
            greater = z;
        }
        else {
            z->next = pivot;
            pivot = z;
        }
    }
    less = quick_sort(less, comp);
    greater = quick_sort(greater, comp);

    if (less == NULL) a = pivot;
    else {
        for (a = z = less; z && z->next; z = z->next) ;
        z->next = pivot;
    }
    for (z = pivot; z->next; z = z->next) ;
    z->next = greater;
    return a;
}

int add_person(int id)
{
    PERSON_t *data;
    data = (PERSON_t *)malloc(sizeof(PERSON_t));
    data->id = id;
    printf("ID->%d\n", data->id);
    scanf("%10s", data->name);
    scanf("%10s", data->address);

    data->next = NULL;
    if (head == NULL) {
         head = data;
         tail = data;
    } else {
        tail->next = data;
        tail = data;
    }
    return NO_PROBLEM;
}

void print_person(PERSON_t *p)
{
    for (; p; p = p->next) printf(" %s %s\n", p->name, p->address);
    putchar('\n');
}

int compare_name(PERSON_t *a, PERSON_t *b)
{
    return strcmp(a->name, b->name);
}

int compare_address(PERSON_t *a, PERSON_t *b)
{
    return strcmp(a->address, b->address);
}


実行例

1.追加入力  2.表示  3.名前でソート  4.住所でソート  0.終了: 1 ccc tokyo
ID->1
追加完了
1.追加入力  2.表示  3.名前でソート  4.住所でソート  0.終了: 1 aaa osaka
ID->2
追加完了
1.追加入力  2.表示  3.名前でソート  4.住所でソート  0.終了: 1 ddd kyoto
ID->3
追加完了
1.追加入力  2.表示  3.名前でソート  4.住所でソート  0.終了: 1 bbb nagoya
ID->4
追加完了
1.追加入力  2.表示  3.名前でソート  4.住所でソート  0.終了: 2
 ccc tokyo
 aaa osaka
 ddd kyoto
 bbb nagoya

1.追加入力  2.表示  3.名前でソート  4.住所でソート  0.終了: 3
並べ替え完了
1.追加入力  2.表示  3.名前でソート  4.住所でソート  0.終了: 2
 aaa osaka
 bbb nagoya
 ccc tokyo
 ddd kyoto

1.追加入力  2.表示  3.名前でソート  4.住所でソート  0.終了: 4
並べ替え完了
1.追加入力  2.表示  3.名前でソート  4.住所でソート  0.終了: 2
 ddd kyoto
 bbb nagoya
 aaa osaka
 ccc tokyo

1.追加入力  2.表示  3.名前でソート  4.住所でソート  0.終了: 0


この問題の出典は何ですか?

追記

また、降順についても、わかりやすい書き方がしたいです。

a と b を入れ替えて比較する関数を用意すればよいでしょう。

int compare_name_rev(PERSON_t *a, PERSON_t *b)
{
    return strcmp(b->name, a->name);
}

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 87.79%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る