
リスト構造のソートで悩んでます。プログラムの内容はファイルからデータをリスト構造の構造体に読み込み、名前順にソートし結果を表示する。というものです。データの追加や削除はできるのですがソートとなると頭が混乱してしまいお手上げ状態になってしまいました。。。。。
読み込み用のデータとプログラムソースを以下に記載するのでどなたか良きアドバイスをお願いします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で質問しましょう!
このQ&Aを見た人はこんなQ&Aも見ています
-
プロが教える店舗&オフィスのセキュリティ対策術
中・小規模の店舗やオフィスのセキュリティセキュリティ対策について、プロにどう対策すべきか 何を注意すべきかを教えていただきました!
-
連結リスト 要素の入れ替え
C言語・C++・C#
-
C言語でリストのソートについて質問します。以下のmain()文を用いた
C言語・C++・C#
-
#include <Windows.h>というヘッダファイルについて
C言語・C++・C#
-
-
4
ファイルから読み込んだデータを構造体に格納できますか?
C言語・C++・C#
-
5
迷路を脱出する経路探索プログラムをC言語で作成するには?
C言語・C++・C#
-
6
関数から配列を返すには?
C言語・C++・C#
-
7
構造体のリストをソートしたい。
C言語・C++・C#
-
8
構造体のメンバをfor文で回したい
C言語・C++・C#
-
9
線形リストのソートについて
C言語・C++・C#
-
10
C言語の構造体にてバブルソートが上手くいきません‥
C言語・C++・C#
-
11
バッファとは何ですか
C言語・C++・C#
-
12
sscanfとscanfの違いがよくわからないのですが、簡単に優しく教えて下さい。 お願い致します。
C言語・C++・C#
-
13
fgetsなどのときのstdinのバッファを消すには?
C言語・C++・C#
-
14
漢字のソートについて
C言語・C++・C#
-
15
数字以外が入力されたらエラー文を出したい。
C言語・C++・C#
-
16
テキストファイルの行数を取得する方法(C言語
C言語・C++・C#
-
17
C言語でファイル名を取得
C言語・C++・C#
-
18
csvファイルを構造体に格納したいです
C言語・C++・C#
-
19
双方向リストのバブルソートについて
C言語・C++・C#
-
20
【C言語】構造体内の領域解放(free)の仕方
C言語・C++・C#
関連するカテゴリからQ&Aを探す
おすすめ情報
このQ&Aを見た人がよく見るQ&A
デイリーランキングこのカテゴリの人気デイリーQ&Aランキング
-
System.IO.Directory.GetFiles...
-
VB.NETでファイル名順にファイ...
-
あるディレクトリ内のファイル...
-
Excelですべての組合せ(重複組...
-
ファイル名「1.jpg ~10.jpg~...
-
文字列をソートする方法
-
配列の問題
-
ブック.csvを開かずに他のブッ...
-
DataGridViewの昇順降順。
-
VB6でデータを昇順に並べ替える
-
VBScriptで配列のソートをする...
-
excel VBA の条件をつけての列...
-
主キーソート(キーの優先順位...
-
DataGridViewでのソート制御
-
C# DataTable ソートについて
-
C# DataGridView のヘッダーセ...
-
datagridviewの並べ替え
-
DataGridViewの複数列を連動し...
-
IPアドレスのSORTについて
-
C++ 入力した3つのint型の整数...
マンスリーランキングこのカテゴリの人気マンスリーQ&Aランキング
-
System.IO.Directory.GetFiles...
-
VB.NETでファイル名順にファイ...
-
ファイル名「1.jpg ~10.jpg~...
-
C# DataTableの行をソートしてD...
-
あるディレクトリ内のファイル...
-
Excelですべての組合せ(重複組...
-
文字列をソートする方法
-
数字文字列のソート方法
-
DataGridViewの複数列を連動し...
-
VBScriptで配列のソートをする...
-
2次元配列を複数項目でソートし...
-
C# DataGridView のヘッダーセ...
-
VBScriptで重複レコードを削除...
-
excel VBA の条件をつけての列...
-
リスト構造のソートで悩んでま...
-
構造体配列のソート
-
qsort/クイックソートについて
-
DataGridViewの昇順降順。
-
excel VBA リストビューの行...
-
Excel VBA で別シートにデータ...
おすすめ情報