• ベストアンサー

Linked List(線形リスト)を使ったデータのソート

大学の、Cの課題で、困っています。 どこが違うのか教えていただけたら嬉しいです。 【課題】 1行に1つの数値データを、複数行入力すると、 このデータを1行ずつ読んでいって、それをひとつの構造体として保持し、 数値データの小さい順にリンクされるようなLinked Listとなるようにプログラムを作る。 入力したデータが数値だったら、Linked Listを先頭から巡り、それを挿入すべき場所を見つける。 そしてデータを格納するための構造体の領域をmalloc関数で確保し、そこにデータを入れ、実際にリストに挿入する。 読み込むべき入力データが無くなったら、最後にLinked Listで保持しているデータを1行ずつ書き出してみる。 【変な結果が出るプログラム】 #include<stdio.h> main() { int c, n, *nextp; void *malloc(size_t size); struct listdata{ int i; struct listdata *nextp; }; struct listdata *hajime; struct listdata *pointer; hajime = NULL; while ( ( c = getchar() ) != EOF ){ if ( '0' <= c && c <= '9' ){ n = n * 10 + ( n - '0' ); } pointer = ( struct listdata *) malloc ( sizeof (struct listdata) ); pointer -> i = n; hajime = pointer -> nextp; } printf ( "%d\n", nextp ); pointer = hajime; while ( pointer != NULL ){ printf ( " %d\n", pointer -> i ); pointer = pointer -> nextp; } } よろしくお願いします(>_<)

質問者が選んだベストアンサー

  • ベストアンサー
noname#89477
noname#89477
回答No.16

#14のsakatomoです。 >for文の処理が終わってからも、最後にi++をしているということですね そうではなくて、i=0~4の5回繰り返した直後(iが4の時)、i++を実行してiが5になったために繰り返し処理を終了したのです。 つまり、i++はその条件を満たした時のみfor文の最後に行われ、i<5の判定は繰り返し処理の最初に行われるからです。 (i>5の判定は6回(0~5)行われます) >for文の後にNULLになる意味がわかりました これもpが最後にNULLで終わると考えるよりは、pがNULLになったから終わったと考えるのが正しいと思います。

halunah
質問者

お礼

あー!! そっか、そうですよね! だから、for文が終わるんですね。 アホでごめんなさい。。 ありがとうございます。 本当に、いろいろ勉強になりました。 とても感謝しています。 何にもお返しができないのが残念です。 本当にありがとうございました!

その他の回答 (15)

  • BLUEPIXY
  • ベストアンサー率50% (3003/5914)
回答No.15

#14>不快な思いをされたようでしたら、お詫び申し上げます。 いえいえ、問題ないです。 同じようなアルゴリズムを使えば同じようなソースになるというのはしょうがないですしね。 アルゴリズムとしては普通で、大いばりでオレが考えたなんていうほどのものでもないですし、むしろ、アルゴリズムとして合ってると確証が得られて少し嬉しいですね。 表現の方法は色々あって、やり方もこれ以外にも色々あると思いますので、逆に質問者さんが、これしかないみたいに思われないといいなと思います。

noname#89477
noname#89477
回答No.14

#13のsakatomoです。 インデント(段落)が付けられないため非常に見にくいソースで大変ですが、一生懸命にご理解されている様子がうかがえて大変うれしく思っております。 例を挙げて説明したいと思います。 線形リストに便宜的に(p1,p2,p3)が登録されており(p1->i < p2->i < p3->i)の関係にあるとします。 今たとえばnewをp2とp3の間に入れたいとします。 その時にはbefには前回のpのポインタ(p2)がセットされています。 つまりhalunahさんのプログラムではこれ(p2)をカウントして探し出していたのですが、(new->i > p->i)の関係にある場合(つまりfor文による繰り返しが継続されている状態)にp(p2)をberに代入して保存しているのです。 もし、わかりにくい場合には bef = p; を削除して for ( p=head ; p!=NULL ; bef = p, p=p->next ){ と書き換えることもできます、こうすると更新前のpをbefに保存しているのがわかりやすくなる反面、コメントが入れにくくなります。 (これをカンマオペレーションと言いますが、",(カンマ)"で区切ることで複数の文を連続して動作させられます) それから(p == NULL)の判定ですが、これはfor文の( ;p != NULL; )の判定の真逆の判定になります。 for文から抜ける条件は、上記NULLによる判定の他にnewを挿入後のbreakによる場合があるためです。 つまり(p==NULL)であるということは、線形リスト中に未挿入の状態(new->iが最大値)にあることを意味しています。 なぜならば、(p==NULL)になるのは(p = p3->next)の時だけだからです。 そしてこの時には、befにはp3がセットされていますのでp3->nextにnewをセットすれば線形リストの最後にnewがセットされることになります。 それから最後に、良く見てみたら#5のBLUEPIXYさんのプログラムとロジックがほとんど同じになっていました。 もちろん盗用ではなくオリジナルなのですが、インデントの付かないソースは私にとって非常に難解であるためBLUEPIXYさんのソースを解読する技術がなかったことによるものです。 不快な思いをされたようでしたら、お詫び申し上げます。 と言うことで、BLUEPIXYさんの書かれたプログラムが関数化した最終的な模範解答であると思います。

halunah
質問者

補足

なるほど~!! 次のために、bef = p; と書いていたんですね。 よくわかりました!ありがとうございます。 p == NULL のことですが、 未挿入の状態のとき、なぜ、p == NULL になっているのかが、わからなかったのは、 初めに、p = NULL;と書いているわけでもないし、 for ( p=head ; p!=NULL ; p=p->next ){ を、途中でbreakせずに最後まで全部まわした場合、p!=NULLの状態で終わるから、 pは、p3を指していることになって、NULLではないと思っていたからだったのですが、 今、簡単なfor文で試してみたら、 たとえば、 for ( i=0 ; i<5 ; i++ ){ ~~ } printf ( "%d", i ); と書くと、iは、4とプリントされると思っていたのが、5と出たので、納得しました。 基本的なことがわかっていなかったようです。 for文の処理が終わってからも、最後にi++をしているということですね。 それなら、p!=NULLで終わったはずのpが、for文の後にNULLになる意味がわかりました。 でも、sakatomoさんの説明してくださった 「for文の( ;p != NULL; )の判定の真逆の判定」という考え方とはまた違う気がするのですが、 この考え方で合っていますか?

noname#89477
noname#89477
回答No.13

sakatomoです。 実際にコンパイル&リンクして実行してみました。 特に動作が不安定ではないようでしたが。 それからコンパイル時に"warning"がたぶん出ていると思うのですが、 #include<stdlib.h> が必要です。 せっかくコンパイルして動かしてみたので、チョットソースをいじってみましたので、参考にしていただければ幸いです。 なるべくわかりやすくするには、無駄な変数の使用を減らして、判定処理を少なくするのがポイントです。 n,m,j,*next,*pointerを使わないようにして、その代わりに*bef(直前のポインタ)を使うようにしました。 それからどうでもいいことですが、コメントは"//"を使った方が"*/"が抜けていたときのトラブルを考えるとリスクが少なくて済みます。 (最近のCは、ほとんど"//"が使えますから) #include<stdio.h> #include<stdlib.h> void main() { int c, b; //n, m, j, *next; struct listdata { int i; struct listdata *next; }; struct listdata *head, *new_, *p, *bef; // *pointer, /* ↑ *headは常にリストの先頭、*new_は新しく入ってきた数値をまず入れておくところ、*pointerは代入用、*pはfor文用 */ head = new_ = NULL; // pointer = b = 0; //n = m = 0; while ( ( c = getchar() ) != EOF ){ if ( '0' <= c && c <= '9' ){ b = b * 10 + c - '0'; } else if ( c == '\n' ){ //m++; new_ = ( struct listdata *) malloc ( sizeof(struct listdata) ); new_->i = b; new_->next = NULL; if ( head == NULL ){ /* リストが空だったら */ head = new_; } else { /* リストに1つ以上入っていたら */ for ( p=head ; p!=NULL ; p=p->next ){ /* headの次から今まで入ったものまで */ if ( new_->i <= p->i ){ if(p == head){ /*----- (最小値)先頭に挿入 */ new_->next = head; /* headの前にnew_を入れて */ head = new_; /* それをheadにする */ } else { /*----- 途中に挿入 */ bef->next = new_; /* 新領域(new_)のポインタを直前(bef)の次ポインタにセット */ new_->next = p; /* 直後(p)ポインタを新領域(new_)の次ポインタにセット */ } break; /* 挿入済みなのでループから抜ける */ } bef = p; /* 直前のポインタを保存(bef->next を変える場合に使用) */ } if(p==NULL){ /*----- (最大値)末尾に挿入 */ bef->next = new_; /* 新領域(new_)のポインタを直前(bef)の次ポインタにセット */ } } b = 0; //n = 0; } } printf ( "\n" ); for ( p=head ; p!=NULL ; p=p->next ){ printf ( "%d\n", p->i ); } printf ( "\n" ); } それから関数の作り方を覚えたら、入力の部分やnewの挿入の部分を関数化することで綺麗な機能分けになると思います。 簡単なプログラムを簡潔に組めないと、難しいプログラムを簡潔に組むことはできません。 もちろん、halunahさんがここまでプログラムを組めるようになっただけでも、スゴイことですよ。

halunah
質問者

お礼

とってもシンプルになりましたねぇ! ちゃんと動きました。ありがとうございます。 でも、わからないところが2つあります。 いくら考えてもわかりません。教えてください。 /*----- 途中に挿入 */ bef->next = new_;  /* 新領域(new_)のポインタを直前(bef)の次ポインタにセット */ new_->next = p;  /* 直後(p)ポインタを新領域(new_)の次ポインタにセット */ の後に、 bef = p;  /* 直前のポインタを保存(bef->next を変える場合に使用) */ というのがありますが、 この3行は、 befの次をnewにして、その次にnewより大きかったpが来るようにして、 その後、pをbefに代入するということですよね? そうすると、pの次がnewで、その次がまたpとなってしまう気がするのですが、、 でもちゃんと動いていますよね…不思議です。 もうひとつ、 if(p==NULL){ bef->next = new_; これは、直前にfor文で、最後、pは!=NULLのところ(それまでで1番大きい数の入っている構造体) を指していると思うのですが、p==NULLの場合というのはあるのでしょうか? また、bef->next = new_; の、befはどこで、リンクリストの最後だと定義されているのですか? なかなか解決しなくて、申し訳ありません。 教えてください。よろしくお願いします。 関数の作り方、この間わかりました。そうですね、使ってみようと思います。 ありがとうございます。

halunah
質問者

補足

あ、わかりました! すみません。 途中に挿入したら、break;するから、 bef = p; は関係ないんですね。 それで、p == NULL の時、bef->next = new_; とする意味はわかりました。 でも、new_がどれよりも大きかった時は、p == NULL であるというのが、なぜかわかりません。 それから、 /*----- 途中に挿入 */ bef->next = new_;  /* 新領域(new_)のポインタを直前(bef)の次ポインタにセット */ new_->next = p;  /* 直後(p)ポインタを新領域(new_)の次ポインタにセット */ これの、befがどこから出てきたのかわかりません。 befは、何のnextなのか書いていないのに、なぜちゃんと繋がるのでしょうか? よろしくお願いします。

  • BLUEPIXY
  • ベストアンサー率50% (3003/5914)
回答No.12

>もし、どこか間違いに気付いたら、コメントをお願いします。 3,6,9,2,5 とか 3,3,3,3,2 とかの場合をトレースしてみるといいかも。 少なくとも、 for ( p=head->next ; p!=NULL ; p=p->next ){ でリストをたどっている時にリストを変更したら、 ループの継続はできるとは限らないことに注意 また、リストを挿入する条件として、 if ( new->i <= p->i ){ のようにイコールの場合があってはまずいのじゃないか?

halunah
質問者

お礼

そうですね、 if ( new->i <= p->i ){ のイコールがあると、 2回同じものが入ってしまいますね。 ありがとうございます! >リストをたどっている時にリストを変更したら、 >ループの継続はできるとは限らないことに注意 たしかに。。 だったら、変更した直後にbreak;すればいいと思ってやってみましたが、変わりませんでした。 とにかく、今まで入っているものより大きい数値が入ってきたり、同じ数値が入ってきたりすると、おかしくなるようなので、for文の中を考えなおします。 数学より難しいかもしれませんね、C言語って。

noname#89477
noname#89477
回答No.11

#10のsakatomoです。 チョット私も言い方が・・・(^_^; 変数には「定義文」と「実行文」とがあります。 (実行文とは、#10で"使用"と言っていたものです) 定義文は実行文よりも先に1回だけしておく必要があります。 pointerの場合 struct listdata *pointer; が線形情報ポインタの定義文となります。 malloc(),memset()にしても、これらは関数の呼び出しになりますので「実行文」となります。 (補足説明として、 int i = 3; といった書き方がありますが、こちらは定義文と実行文がいっしょになったものと言えます。 またC++になると、newとかを使いますがこのへんは定義文?実行文?の切り分けが微妙です) >1から自分でプログラムを書くことができました それはおめでとうございます。 >正しい結果が出る時と出ない時 こういうのが一番やっかいなんですよね。 (でもコンパイル&リンクできたってことですからスゴイ) >先生に聞いてみます 懐かしい言葉の響き 一度覚えてしまえば、この苦労を繰り返すことはありませんから、少しずつガンバってください。

halunah
質問者

補足

わかりました!今気付きました! memset()をmalloc()した後に入れろと言われて、 私はよくわからないまま、 最初の方の、void *malloc(size_t size);の後に入れてしまったから、ああいうことになったのでした。 pointer = ~~~ malloc(~);の後ということだったんですね。アホでした。。 そうですよね、実行文ですよね。 あー解決。お騒がせいたしました。 あはは、「先生に聞いてみます」って懐かしいですか~。 それが、今日、先生が時間なくて教えてもらえませんでした。 というわけで、ふたたび添削お願いできたらと思います。 #include<stdio.h> main() { int c, b, n, m, j, *next; struct listdata { int i; struct listdata *next; }; struct listdata *head, *pointer, *new, *p; /* ↑ *headは常にリストの先頭、*newは新しく入ってきた数値をまず入れておくところ、*pointerは代入用、*pはfor文用 */ head = pointer = new = NULL; b = n = m = 0; while ( ( c = getchar() ) != EOF ){ if ( '0' <= c && c <= '9' ){ b = b * 10 + c - '0'; } else if ( c == '\n' ){ m++; new = ( struct listdata *) malloc ( sizeof(struct listdata) ); new->i = b; new->next = NULL; if ( head == NULL ){ /* リストが空だったら */ head = new; } else { /* リストに1つ以上入っていたら */ if ( new->i < head->i ){ /* headより小さかったら */ new->next = head; /* headの前にnewを入れて */ head = new; /* それをheadにする */ } else { for ( p=head->next ; p!=NULL ; p=p->next ){ /* headの次から今まで入ったものまで */ if ( new->i <= p->i ){ pointer = head; for ( j=0 ; j<n ; j++ ){ /* pointerを、newを入れたい所の前に設定 */ pointer = pointer->next; } new->next = pointer->next; /* pointerとその次の間にnewを入れる */ pointer->next = new; } else { n++; /* newがpより大きい時、nが増える */ } } if ( n == m-2 ){ /* newがどれよりも大きかった時、nは、headとnew以外の構造体の数 */ pointer = head; for ( j=0 ; j<n ; j++ ){ pointer = pointer->next; /* pointerを最後尾に設定 */ } pointer->next = new; /* 最後尾の次にnewを付け加える */ } } } b = n = 0; } } printf ( "\n" ); for ( p=head ; p!=NULL ; p=p->next ){ printf ( "%d\n", p->i ); } printf ( "\n" ); } もし、どこか間違いに気付いたら、コメントをお願いします。

noname#89477
noname#89477
回答No.10

#8のsakatomoです。 無視していたわけではなく、答えに悩んでいて遅れてしまいました。 >pointerを最初に使うところ 変数(pointer)には、定義と使用(参照、代入)があります。 そのような意味での「使われている」なので、最初に「使用」されているのは pointer = ( struct listdata *) malloc ( sizeof (struct listdata) ); // 線形情報領域の確保&アドレスの代入 という意味です。 質問の主旨から外れますが、開発マシンはWindowsではないのですか?

halunah
質問者

補足

sakatomoさん、 長い間付き合ってくださって、本当にありがとうございます! では、memsetのところは、定義の部類に入るんですか。 たしかに使用ではないですね。参照のような気もしますが… そうなんです、Macです。色々とやりにくいです。。 話は戻りますが、 今日、リスト構造のことがようやく理解でき、 1から自分でプログラムを書くことができました。 でも、正しい結果が出る時と出ない時があります。 いくら見直しても、どういう時におかしくなるのかわからないので、明日先生に聞いてみます。 先生が教えてくれなかったりわからなかったりしたら、また助けを求めるかもしれません。 その時はよろしくお願いします(>_<)

noname#89477
noname#89477
回答No.9

ごめんなさい。No.2のsakatomoです。 肝心なことを書くのを忘れていました。 「pointerが宣言されていませんと言われます」 などのエラーをコンパイルエラーと言いますが、これは必ず最初に出てくるものから解決していかないといけません。(つまり上の行から) つまり最初に変数定義があって、初めてその変数を使用することができるからです。 まず、コンパイルエラーを取って動かしてからが本当のデバッグ(確認テスト)になります。 (現在はたぶん机上デバッグ?) 動くようになれば、たとえばprintf()などで動きや値がわかりますので(デバッガを使う手もありますが)とにかくコンパイルエラーを早急に取ることを期待いたします。

halunah
質問者

補足

もう、後ろの方は、消してしまって、 最初の動作の部分だけをprintfで確認したりすればいいんですね。 ちなみに、デバッグ?は、 毎回、Fetchでアップロードしてtelnetで試しています。

noname#89477
noname#89477
回答No.8

どうも、sakatomoです。 最初覚えることが多いし、それぞれの関連を考えるのが大変だと思いますが、少しずつ覚えていけば必ずわかるようになるので、ガンバってください。 もう、No.5さんの方がサンプル(正解?)をUpされているのでいいのかも知れませんが、No.2に対する返信をしたいと思います。(回答にはなっていませんが) 「pointerが宣言されていませんと言われます」とのことですが、pointer の宣言は struct listdata *pointer; と、すでにされているハズです。 スペルミスなのか、struct listdataの定義ですでにエラーが出ているのか。 また、int *pointer; を定義したらすでに struct listdata *pointer; で定義されているのですから、2重定義エラーになるはずです。(たぶん) また「pointerが宣言されていませんと言われます」は最初にpointer が使われているのは、 pointer = ( struct listdata *) malloc ( sizeof (struct listdata) ); ですので、ここでまず出ているはずです。 実際に見られるわけではないので、お互いにじれったい部分がありますが、根気強くガンバってください。 ご健闘をお祈りいたします。

halunah
質問者

補足

すぐに回答してくださったのに、 反応が遅くなって申し訳ありません。 そうですよね、int *pointer; では、 二重に定義してしまうことになりますよね。 でも、 memset(pointer, 0, sizeof( *pointer ) ); が、pointerを最初に使うところではないのですか? これの前にpointerを定義しないといけないのかなと思ったのですが、そういうわけではないのでしょうか?

  • BLUEPIXY
  • ベストアンサー率50% (3003/5914)
回答No.7

>でも、私には書いてあることがさっぱりわからないので、 がっくりorz Linked List に挿入するということは、どういうことか、図でも描いてみるといいかも・ あと、mallocしたメモリは、解放するべきということがあるかもしれない。

  • BLUEPIXY
  • ベストアンサー率50% (3003/5914)
回答No.6

#5は、マイナスの数値がチェックではじかれる! と思ったら、もとのプログラムもマイナスの数値を許可しないからいいか・

関連するQ&A

  • 線形リスト

    こんにちわ。今、大学で線形リストの勉強してるのですがよくわかりません。 ↓のプログラムで (1)10個のIDを受け取って受け取った順にリストを作るプログラム(各要素の値のアドレスとそのnextの値を表示してリストになっていることを確認する。) (2) (1)のプログラムを拡張して、リストを作ったあと、1から10までの間の整数nを入力として受け取り、リストのn番目の要素のIDを表示プログラムを書け。 の2つのことをしたいんですけど、どのようにすればいいのですか?どなたか回答おねがいします。 #include<stdio.h> #include<stdlib.h> struct list{ int ID; struct list *next; }; int main(int argc, char* argv[]) { struct list *top; top=(struct list *)malloc(sizeof(struct list)); //struct list 型の大きさの領域を1つ確保 //topがそこを指している状態にする //printf("IDを10個入力してください"); if(top == NULL){ //メモリが足りないと値がNULLになってします printf("メモリは確保できません\n"); exit(1); //強制終了。プログラムはココで終わってしまいます } top->next=NULL; top->ID=1; //ポインタtopが指している構造体のIDの値を変えている top->next=(struct list*)malloc(sizeof(struct list)); //もう1つ作ります //top->next==NULL (メモリ確保に失敗)の処理は省略 (top->next)->next=NULL; (top->next)->ID=5; //これで下図のような状態になります; return 0; }

  • 単方向リスト

    #include<stdio.h> #include<stdlib.h> #include<string.h> struct Address{ char name[100]; char tel[100]; char email[100]; }; struct AddressList { struct Address addr; //データそのもの struct AddressList *next; //後続ノードへのポインタ struct AddressList *prev; }; struct AddressList *this,*last,*new,*first; struct Address *addr; /*--------ここからmain関数------------*/ int main(void){ int n,i; //何番目に入れるか? char quit[100]; //繰り返しを止める時に利用。 first=last=NULL; //まず初期化 addr =(struct Address *)malloc(sizeof(struct Address)); if(addr==NULL){ fprintf(stderr,"malloc:error\n"); exit(1); } while(-1){ printf("整数を入力してください。\n"); scanf("%d",&n); printf("名前を入力してください。\n"); scanf("%s",addr->name); printf("電話番号を入力してください。\n"); scanf("%s",addr->tel); printf("メールアドレスを入力してください。\n"); scanf("%s",addr->email); new =(struct AddressList *)malloc(sizeof(struct AddressList)); //新たに加えるリストの動的メモリー確保 if(new==NULL){ fprintf(stderr,"malloc:error\n"); exit(1); } new->addr=addr; //ここでエラーが発生します。 new->next=NULL; incompatible types in assignment とエラーがでます。 型はあってると思うんですが、、、 よろしくおねがいします。

  • 線形リストについて。

    このたび線形リストを学習し、自分でサンプルコードを書くことにしました。 しかし、動かすことが出来ず、理解することが出来なかったため、ご相談致します。 コード: #include <stdio.h> #include <stdlib.h> #define N 10 typedef struct node *link; struct node { int item; link next; }; void main() { int i; link head ,t; head = NULL; //リストに要素を入れる。 for(i = 0,t = head; i < N; i++, t = t->next) { t = malloc(sizeof *t); t ->next = NULL; t ->item = i; } //リストを表示する for(t = head; t != NULL; t = t->next) { printf("%d\n", t->item); } } 実行結果: リストを表示するのfor文内、t->itemでエラー。 原因はheadを上手くポインタで指せていないことにあると思います。 お聞きしたいことは2点です。 1.なぜ意図したように上手く動かないのか。 2.このように動かしたい場合、何処を変更すれば良いのか。 以上です。 宜しくお願いします。

  • 双方向リストのバブルソートについて

    双方向リストをバブルソートを用いてソートしたいです。 下記がプログラム(一部)ですが、ソートした後にリスト表示すると 無限ループに陥ります。 どこがいけないのでしょうか。 #include <stdio.h> #include <stdlib.h> struct cell{ int data; struct cell *next, *prev; }; void insert_head(struct cell **head, int num){ struct cell *p, *p1; p = *head; p1 = make_cell(); *head = p1; p1->data = num; p1->next = p; if(p1->next != (struct cell *)NULL){ p1->next = p; p->prev = p1; } } void print_list(struct cell *head){ struct cell *p; p = head; printf("data = \n"); while(p != (struct cell *)NULL){ printf("%d\n", p->data); p = p->next; } } void sort_list(struct cell **head){ struct cell *p, *p2; int i, n; n = 0; p = *head; while(p->next != (struct cell *)NULL){ p = p->next; n++; } for(i = 0, p = *head; i < n-2; i++){ if(p->data > p->next->data){ if(p == *head){ *head = p->next; }else{ p->prev->next = p->next; } p2 = p->next; p->next = p->next->next; p->next->next = p; p->next->next->prev = p; p->next->prev = p->prev; p->prev = p2; }else p = p->next; } } int main(void){ struct cell *head = (struct cell *)NULL; int n; while(1){ printf("1:Insert head 2:Insert tail 3:Delete 4:List 5:Sort 6:Exit\n"); scanf("%d", &n); switch(n){ case 1: printf("num = "); scanf("%d", &n); insert_head(&head, n); break; case 2: printf("num = "); scanf("%d", &n); insert_tail(&head, n); break; case 3: printf("num = "); scanf("%d", &n); delete_cell(&head, n); break; case 4: print_list(head); break; case 5: sort_list(&head); break; case 6: return 0; break; } } }

  • リストの削除について(構造体)

    リストの削除のプログラムを実行して行ってみると、リストの削除処理中にプログラムが終わって変更後処理がうまく表示されません。どこが間違っているかが分からないしだいです。返答のほどよろしくお願いいたします。 #include<stdio.h> #include<malloc.h> #include<string.h> struct list{ char name[20]; int age; struct list *next; }; void main(void) { struct list *head, *p, *n, *old; char key[20]; /*ダミーノード作成*/ head = (struct list*)malloc(sizeof(struct list)); old = head; while(p = (struct list*)malloc(sizeof(struct list)), printf("name age入力\n"), scanf("%s %d", p -> name, &p -> age) != EOF){ old -> next = p; old = p; } free(p); old -> next = NULL; p = head -> next; printf("変更前リスト\n"); while(p != NULL){ printf("name:%s age:%d\n",p -> name, p -> age); p = p -> next; } printf("削除key入力(name)\n"); gets(key); n = head; while(n != NULL){ old = n; n = n -> next; //printf("n -> name %s\n", n -> name); if(strcmp(n -> name, key) == 0){ printf("%s削除\n", key); //printf("n -> name %s old -> name %s\n", n -> name, old -> name); old -> next = n -> next; } } p = head -> next; printf("変更後リスト\n"); while(p != NULL){ printf("name:%s age:%d\n", p -> name, p -> age); p = p -> next; } }

  • 線形リストのソートについて

    データ構造を線形リストとして、情報を管理するプログラムのソートについてです。 以下のプログラムはデータを入れ替えて、その後アドレスを入れ替えるようにしてソートを行っていますが、そうではなく線形リストなのでつなぎ替えるようにしてソートを行うプログラムを作成したいのですがわからないのでご教授をお願い致します。ソートは逐次決定で行ってます。 構造体の宣言として、nameとageとnextは氏名と年齢と次のポインタを指します。NAME_SORT、AGE_SORTはマクロです。 struct sortlist(struct PERSON *head) { int menu; struct PERSON person; /* 情報 */ struct PERSON move_person; /* 比較していく情報 */ struct PERSON work; /* 情報の一時的保存 */ struct PERSON temp; /* 作業用 */ struct PERSON temp_address; /* アドレス作業用 */ printf("ソート機能を選択:"); printf("%d:氏名\n",NAME_SORT); printf("%d:年齢\n",AGE_SORT); /* 交換処理 */ for(person = head; person -> next != NULL; person -> person -> next) { work = person; /* 交換データの探索 */ for(move_person = person -> next; move_person != NULL; move_person -> next) { switch(menu) { case NAME_SORT: if(strcmp(work -> name, move_person -> name) > 0) { work = move_person; } break; case NAME_SORT: if(work -> age > move_person -> age) { work = move_person; } break; default: printf("機能以外が選択されました"); return head; } if(work != person) { /* 情報の交換 */ temp = *person; *person = *work; *work = temp; /* アドレスの交換 */; temp_address = employee -> next; person -> next = work -> next; work -> next = temp_address; } } } } printf(“ソート完了”); }

  • 線形リスト(C言語)

    線形リストでn番目のIDを表示するプログラムを作っていますが、なぜか実行すると強制終了してしまいます。 コンパイルエラーは起きていないので、原因がさっぱりわかりません。 どなたかご教授お願いします。 #include <stdio.h> #include <stdlib.h> struct list{ int ID; struct list *next; }; int main(void) { struct list *top, *a; int i, n, x; a = NULL; for(i = 1; i < 11; i++) { printf("%d番目のIDを入力: " ,i); scanf("%d" ,&x); top = (struct list *)malloc(sizeof(struct list)); top->ID = x; top->next = a; a = top; } printf("何番目のIDを表示しますか: "); scanf("%d" ,&n); for(i = 1; i < 11; i--) { if(i == n) printf("%d" ,top->ID); top = top->next; } free((top->next->next->next->next->next->next->next->next)->next); free((top->next->next->next->next->next->next->next)->next); free((top->next->next->next->next->next->next)->next); free((top->next->next->next->next->next)->next); free((top->next->next->next->next)->next); free((top->next->next->next)->next); free((top->next->next)->next); free((top->next)->next); free(top->next); free(top); return 0; }

  • アルゴリズム 線形リスト

    最近リストについて習い始めました。入力したデータと同順に並ぶリストを作成しようと思い、コードを打ったのですが…動作中止の表示がでてしまいました。どこが間違っているのか、ずっと悪戦苦闘して組んでいるのですが、全く出口が見えてきません。何が間違えているのか、はたまた根本的に違うのか、ご指導して頂けると有難いです。 以下、コードです。 #include <stdio.h> #include <stdlib.h> #include <string.h> struct hito{ char name[20]; int age; struct hito *next; }; void main(void){ struct hito *p, *head, *dummy; char new_name[20]; int new_age; dummy = (struct hito *)malloc(sizeof(struct hito)); head = dummy; dummy->next = p; dummy = p; while (scanf("%s %d" , new_name, &new_age) != EOF) { p = (struct hito *)malloc(sizeof(struct hito)); strcpy(p->name, new_name); p->age = new_age; p->next = head; head = p; } while(p != NULL) { printf("\t%-20s %3d\n" , p->name, p->age); p = p->next; } }

  • C言語のリストのソートについて質問します。

    C言語のリストのソートについて質問します。 こんばんは、aida13です。以前の質問が自己解決しました。回答者のみなさん本当にすみませんでした。 今回はそのアルゴリズムで改善したい点がありましたので投稿させていただきました。以下のソートを実行するとソート自体はうまくいくのですが、見ての通りwhileやifなどを使って何度も実行しなおさないと完全にソートできません(「5 4 3 2 1」→「4 3 2 1 5」(一回ソート))。これを一回でソートできるようにしたいのです。また、降順も同様にそのままsecondとheadを入れ替えたのですが…今度は何度やっても「1 2 3 4 5」→「2 1 3 4 5」(一回ソート)からそれ以上動きません。アドバイスをお願いします。また、出来る限りこの形を保てる形でお願いします。 以下自作ソート #include < stdio.h > #include < stdlib.h > struct ans { int data; struct ans *next; }; struct ans *sort_up(struct ans *head) { int temp; struct ans *second_head; second_head = (struct ans *)malloc(sizeof(struct ans)); second_head = head->next; if( head->next == NULL ) { return head; } else { if( head->data > second_head->data ) { temp = head->data; head->data = second_head->data; second_head->data = temp; sort_up(head->next); } else { sort_up(head->next); } return head; } } struct ans *add_list(int x, struct ans *head) { struct ans *new_head; new_head = (struct ans *)malloc(sizeof(struct ans)); new_head->data = x; new_head->next = head; return new_head; } void show_list(struct ans *head) { if( head == NULL ) { printf("\n\n"); } else { printf("%d ",head->data); show_list(head->next); } } void main() { struct ans *head; head = NULL; head = add_list(1,head); head = add_list(2,head); head = add_list(3,head); head = add_list(4,head); head = add_list(5,head); do { printf("input:"); scanf("%d",&a); if(a==0) { head = sort_up(head); show_list(head); } } while(a==0); }

  • リスト構造のソートで悩んでます。。。

    リスト構造のソートで悩んでます。プログラムの内容はファイルからデータをリスト構造の構造体に読み込み、名前順にソートし結果を表示する。というものです。データの追加や削除はできるのですがソートとなると頭が混乱してしまいお手上げ状態になってしまいました。。。。。 読み込み用のデータとプログラムソースを以下に記載するのでどなたか良きアドバイスをお願いします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){ }

専門家に質問してみよう