リスト構造のソートで悩んでます。プログラムの内容はファイルからデータをリスト構造の構造体に読み込み、名前順にソートし結果を表示する。というものです。データの追加や削除はできるのですがソートとなると頭が混乱してしまいお手上げ状態になってしまいました。。。。。
読み込み用のデータとプログラムソースを以下に記載するのでどなたか良きアドバイスをお願いしますm(_ _)m
○データ
Sakuragi
16
Rukawa
16
Miyagi
17
Akagi
18
Mitsui
18
○ソース
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MENBER 5
typedef struct data{
char name[BUFSIZ];
int age;
struct data *next;
}LIST;
LIST *newLIST(void);
LIST *sort(LIST *);
int main(int argc,char *argv[]){
FILE *fp;
LIST *p;
LIST *np;
LIST *npb;
LIST *head;
char namae[BUFSIZ];
int toshi,i;
if((fp=fopen(argv[1],"r"))==NULL){
printf("no file\n");
exit(1);
}
head = newLIST();
npb =head;
for(i=0;i<MENBER;i++){
np = newLIST();
fscanf(fp,"%s %d",namae,&toshi);
strcpy(np->name,namae);
np->age = toshi;
npb->next =np;
npb = np;
}
sort(head);
for(p=head->next;p != NULL;p=p->next){
printf("%s\t%d\n",p->name,p->age);
}
for(p=head->next;p != NULL;p=np){
np = p->next;
free(p);
}
fclose(fp);
return(0);
}
LIST *newLIST(){
LIST *p;
p = (LIST *)malloc(sizeof(LIST));
p->next = NULL;
return(p);
}
LIST *sort(LIST *head){
}
No.2ベストアンサー
- 回答日時:
ソートするには「リストの順を入れ替える」か「リストの順は変えずにデータを入れ替える」と言う処理が必要です。
第1案 リストの順を入れ替える
リストの順を入れ替えるには、各項目のnextメンバを入れ替えます。
例えば
A→B→C→D→E
の状態でBとDを入れ替えるには
「Bを指す、A->next」と「Dを指すC->next」を入れ替え
「Bの次を指す、B->next」と「Dの次を指す、D->next」を入れ替え
と言う2つの「入れ替え」を行わなければなりません。
「B」を参照している時に「Bを指す、A->next」を知るには「Bの前は何か?」を知る必要があります。
リストの項目が少ないならば、先頭から順にサーチしていけば良いですが、項目が増えればサーチに時間が掛かり、現実的ではありません。
また、nextメンバの入れ替えが煩雑になり、あまり適切とは言えません。
第2案 データの実体を入れ替える
入れ替えの際にnextメンバを変更せず、nameメンバの内容、ageメンバの内容を入れ替えます。
この場合、ソート後に一番末尾になる項目が先頭にある、と言う場合、データの実体の入れ替えが何回も発生します。
もし「データの実体サイズ」が大きいと、メモリアクセスが膨大に発生し、実用にならない速度になります。
第3案 リストの順、データの実体は入れ替えず、リストからデータへの参照のみ入れ替える。
データ構造体とリスト構造体を分離します。
typedef struct data_t {
char name[BUFSIZ];
int age;
} DATA;
typedef struct list_t {
DATA *data;
LIST *next;
} LIST;
void swapLIST(LIST *p1,LIST *p2)
{
DATA *tp;
tp = p1->data;
p1->data = p2->data;
p2->data = p1->tp;
}
LIST *newLIST(){
LIST *lp;
DATA *dp;
lp = (LIST *)malloc(sizeof(LIST));
if(lp==NULL) return(NULL);
dp = (DATA *)malloc(sizeof(DATA));
if(dp==NULL) {free(lp); return(NULL);}
lp->data = dp;
lp->next = NULL;
return(lp);
}
void sort(LIST *top){
LIST *p1;
LSTT *p2;
for(p1=top;p1->next!=NULL;p1=p1->next){
for(p2=p1->next;p2!=NULL;p2=p2->next){
if(strcmp(p1->data->name,p2->data->name) > 0) swapLIST(p1,p2);
}
}
}
int main(int argc,char *argv[]){
FILE *fp;
LIST *p;
LIST *np;
LIST *head;
char namae[BUFSIZ];
int toshi,i;
if((fp=fopen(argv[1],"r"))==NULL){
printf("no file\n");
exit(1);
}
head = NULL;
np = NULL;
for(i=0;i<MENBER;i++){
p = newLIST();
if(p==NULL) break;/*メモリ不足*/
if(head==NULL) head=p;/*最初の1個目*/
if(np!=NULL) np->next =p;/*1つ前があるなら、1つ前のnextをpに繋げる*/
fscanf(fp,"%s %d",namae,&toshi);
strcpy(p->data->name,namae);
p->data->age = toshi;
np=p;
}
sort(head);
for(p=head;p != NULL;p=p->next){
printf("%s\t%d\n",p->data->name,p->data->age);
}
for(p=head;p != NULL;p=np){
free(p->data);
np = p->next;
free(p);
}
スワップ・ソートを行う場合、2つのリストのdataメンバのみ入れ替えれば良いので、かなり処理が軽く、この方法が一番現実的です。
なお、最初に確保するデータが無駄になっているので改良してあります。
3つもアドバイスを頂いて感謝します。
私は3番目のアドバイスを参考にさせてもらいました。
構造体を入れ替えるのではなく中身のメンバを入れ替える部分に
感動を覚えました!!なるほど!!みたいな。
No.4
- 回答日時:
線形リストのソートならマージソートを使ってはどうでしょうか。
ちょうどピッタリのページがありましたのでご紹介いたします。
参考URL:http://www.geocities.jp/ky_webid/algorithm/021.h …
ありがとうございます。
プログラムの勉強は最近はじめたばかりでマージシートという言葉も初めて耳にしました。まだ難しくて分かりませんが少しずつ勉強して理解できるようがんばります(^^)
No.3
- 回答日時:
これだとLISTのメンバが多くなればなるほど重くなりそうですが…。
static int listcmp(const void *a, const void *b)
{
LIST *p, *q;
int d;
p = (LIST *) a;
q = (LIST *) b;
if ((d = p->age - q->name) == 0)
d = strcmp(p->name, q->name);
return d;
}
LIST *sort(LIST *head)
{
LIST *p, *buf;
int n, i;
/* 0個または1個は並べ替える必要がないのですぐ帰る */
if (head == NULL || head->next == NULL)
return head;
/* リストの要素数を数える。 */
for (p = head, n = 0; p; p = p->next, n++);
/* その分のメモリを確保する。 */
if ((buf = (LIST *) calloc(n, sizeof(LIST))) == NULL) {
perror("calloc()");
exit(1);
}
/* 中身を buf の方に移す。 */
for (i = 0, p = head; i < n; i++, p = p->next)
buf[i] = *p;
/* クイックソートする。 */
qsort(buf, n, sizeof(*buf), listcmp);
/* 中身を元に戻す。 */
for (i = 0, p = head; i < n; i++, p = p->next) {
strncpy(p->name, buf[i].name, sizeof(p->name));
p->age = buf[i].age;
}
/* bufはもう不要なのでメモリ開放 */
free(buf);
}
アドバイスありがとうございます。
私はプログラムの知識が少ないのでcallocやp = (LIST *) a;などの
使い方がよく理解できてません。でもアドバイスを有効に活用できるよ
うにがんばって勉強します!!
お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!
似たような質問が見つかりました
- 大学・短大 C言語線形リストの問題です 3 2022/12/22 00:45
- C言語・C++・C# c言語の問題の説明、各所ごとに 5 2023/07/26 11:03
- C言語・C++・C# バイナリファイルをコピーするのにかかる時間を測りたいのですが実行するとFatel error:gli 2 2022/11/03 01:10
- C言語・C++・C# c言語の問題です 3 2023/01/10 16:15
- C言語・C++・C# プログラミングの授業の課題です 1 2023/01/17 22:15
- C言語・C++・C# このプログラミング誰か教えてくれませんか 1 2022/06/02 15:27
- AJAX JavascriptからPHPへのAjax通信でnullが返ってくる 3 2022/08/03 22:00
- PHP 配列の値の更新方法について 1 2022/08/05 09:49
- HTML・CSS CSS のみのタブ切り替えについて 1 2023/01/11 16:47
- C言語・C++・C# C++プログラミングコードにポリモーフィズムを取り入れ方を教えてください。 2 2023/06/09 11:17
このQ&Aを見た人はこんなQ&Aも見ています
-
カンパ〜イ!←最初の1杯目、なに頼む?
飲み会で最初に頼む1杯、自由に頼むとしたら何を頼みますか? 最初はビールという縛りは無しにして、好きなものを飲むとしたら何を飲みたいですか。
-
家・車以外で、人生で一番奮発した買い物
どんなものにお金をかけるかは人それぞれの価値観ですが、 誰もが一度は清水の舞台から飛び降りる覚悟で、ちょっと贅沢な買い物をしたことがあるはず。
-
初めて自分の家と他人の家が違う、と意識した時
子供の頃、友達の家に行くと「なんか自分の家と匂いが違うな?」って思いませんでしたか?
-
この人頭いいなと思ったエピソード
一緒にいたときに「この人頭いいな」と思ったエピソードを教えてください
-
お風呂の温度、何℃にしてますか?
みなさん、家のお風呂って何℃で入ってますか? ぬるめのお湯にゆったり…という方もいれば、熱いのが好き!という方もいるかと思います。 我が家は平均的(?)な42℃設定なのですが、みなさんのご家庭では何℃に設定していますか?
-
線形リストのソートについて
C言語・C++・C#
-
連結リスト 要素の入れ替え
C言語・C++・C#
-
構造体の勉強中です 合計点の高い順に並べ替えがわかりません
C言語・C++・C#
-
-
4
関数から配列を返すには?
C言語・C++・C#
-
5
プログラムでの数字につく”f”の意味
C言語・C++・C#
-
6
セグメントエラー
C言語・C++・C#
-
7
fgetsなどのときのstdinのバッファを消すには?
C言語・C++・C#
関連するカテゴリからQ&Aを探す
おすすめ情報
- ・漫画をレンタルでお得に読める!
- ・【大喜利】【投稿~11/22】このサンタクロースは偽物だと気付いた理由とは?
- ・お風呂の温度、何℃にしてますか?
- ・とっておきの「まかない飯」を教えて下さい!
- ・2024年のうちにやっておきたいこと、ここで宣言しませんか?
- ・いけず言葉しりとり
- ・土曜の昼、学校帰りの昼メシの思い出
- ・忘れられない激○○料理
- ・あなたにとってのゴールデンタイムはいつですか?
- ・とっておきの「夜食」教えて下さい
- ・これまでで一番「情けなかったとき」はいつですか?
- ・プリン+醤油=ウニみたいな組み合わせメニューを教えて!
- ・タイムマシーンがあったら、過去と未来どちらに行く?
- ・遅刻の「言い訳」選手権
- ・好きな和訳タイトルを教えてください
- ・うちのカレーにはこれが入ってる!って食材ありますか?
- ・おすすめのモーニング・朝食メニューを教えて!
- ・「覚え間違い」を教えてください!
- ・とっておきの手土産を教えて
- ・「平成」を感じるもの
- ・秘密基地、どこに作った?
- ・【お題】NEW演歌
- ・カンパ〜イ!←最初の1杯目、なに頼む?
- ・一回も披露したことのない豆知識
- ・これ何て呼びますか
- ・初めて自分の家と他人の家が違う、と意識した時
- ・「これはヤバかったな」という遅刻エピソード
- ・これ何て呼びますか Part2
- ・許せない心理テスト
- ・この人頭いいなと思ったエピソード
- ・牛、豚、鶏、どれか一つ食べられなくなるとしたら?
- ・好きなおでんの具材ドラフト会議しましょう
- ・餃子を食べるとき、何をつけますか?
- ・あなたの「必」の書き順を教えてください
- ・ギリギリ行けるお一人様のライン
- ・10代と話して驚いたこと
- ・大人になっても苦手な食べ物、ありますか?
- ・14歳の自分に衝撃の事実を告げてください
- ・家・車以外で、人生で一番奮発した買い物
- ・人生最悪の忘れ物
- ・あなたの習慣について教えてください!!
- ・都道府県穴埋めゲーム
このQ&Aを見た人がよく見るQ&A
デイリーランキングこのカテゴリの人気デイリーQ&Aランキング
-
System.IO.Directory.GetFiles...
-
C# DataGridView のヘッダーセ...
-
VBA基本構文の作り方 2列の...
-
Excel VBA テキストボックス内...
-
EXCEL VBAのソートについて
-
VB.NETでファイル名順にファイ...
-
Excel2010 /VBA ユーザー設定リ...
-
構造体配列のソート
-
単純挿入ソート法の要素の比較...
-
DirectoryInfo型配列ソート(C#)
-
datagridviewの並べ替え
-
C言語・要素除去
-
プログラミングについて 配列を...
-
csvファイル内にてソートす...
-
【WPF】【C#】【XAML】LISTBOX
-
構造体配列の並べ替え
-
GridViewで列のソートを無効に...
-
datatablesのソートを数字順に...
-
あるディレクトリ内のファイル...
-
excel VBA リストビューの行...
マンスリーランキングこのカテゴリの人気マンスリーQ&Aランキング
-
System.IO.Directory.GetFiles...
-
VB.NETでファイル名順にファイ...
-
C# DataGridView のヘッダーセ...
-
あるディレクトリ内のファイル...
-
C言語・要素除去
-
ファイル名「1.jpg ~10.jpg~...
-
Excelですべての組合せ(重複組...
-
C言語でアナグラムを求めるプロ...
-
2次元配列を複数項目でソートし...
-
C# DataTableの行をソートしてD...
-
DataGridViewソート時に先頭行...
-
n番目に大きい数を求めるアル...
-
DataGridViewの複数列を連動し...
-
VBA基本構文の作り方 2列の...
-
配列の問題
-
10個の整数を入力して小さい順...
-
構造体配列の並べ替え
-
vbでDataTableの抽出コピー
-
リスト構造のソートで悩んでま...
-
DataGridViewの昇順降順。
おすすめ情報