- ベストアンサー
C言語のリストのソートについて質問します
- C言語のリストのソートについて質問します
- リストのソートアルゴリズムは機能しているが、複数回実行する必要があります。一度で完全にソートする方法を知りたいです。
- 降順のソートも同様に問題があります。アドバイスをいただけますか?
- みんなの回答 (9)
- 専門家の回答
質問者が選んだベストアンサー
まずリストの操作では中のデータを操作してはいけません。この場合は単純ですが実際には構造が不明な場合が多いのです。ポインタを繋ぎかえるのが基本的です。 バブルソートは極めて簡単で単純に隣同士を入れ替えるだけです。 struct ans root; struct ans *back,*temp,*last; root.next=head; last=NULL; とすると内側のループは以下のように記述できます。(携帯からなのでコンパイルしていません) for(back=&root;(head=(temp=head->next))!=last;back=temp) if(head->data<temp->data){ temp->next=head->next; back->next=head; head->next=temp; } これを交換する最後のデータがリスト先頭に達するまで繰り返すだけです。 for(last=NULL;(head=root.next)!=last;last=temp) ・・・ return root.next; バブルソートはデータが多いと直ぐ破綻しますが、とりあえず動くようにしてみてください。 動いたらバブルソートの改良、双方向リンク・リストに書き換えみる事です。 バブルソートは昇順に並べる場合には、交換が発生したときに最小値がどうか調べて、最小値を先頭に移動する事で実行時間の短縮ができます。また一度も交換が発生しなければ打ち切ります。 データが数万個以上でも実用的なソートもありますが、それはリンクの操作をマスターしてからですね。
その他の回答 (8)
- 正親町(@Ohgimachi)
- ベストアンサー率43% (110/252)
#7です。ミスがありました。 for(back=&root;(head=(temp=head->next))!=last;back=temp) はfor(back=&root;(head=(temp=head)->next)!=last;back=temp) です。(-o-;)
- asuncion
- ベストアンサー率33% (2127/6289)
>挿入そのものは 2/n でも、 これを「2ぶんのエヌ」と読ませるのは至難の業です。 どう見ても「エヌぶんの2」としか読めません。
- 麻野 なぎ(@AsanoNagi)
- ベストアンサー率45% (763/1670)
済みません、訂正です。 挿入そのものは 2/n でも、それを n個分繰り返すから、全体のオーダーとしては n^2 ですね。 最近ぼけてます。
- 麻野 なぎ(@AsanoNagi)
- ベストアンサー率45% (763/1670)
挿入時にソートなら、挿入の前後でソートができているというのが仮定できるはずなので(少なくとも、挿入した後はソート済み……だから、ひとつ以上挿入したらその時点ではソート完了)処理オーダーはリストでも n / 2 の気がする。 先頭から確認して、大きい/小さい要素に突き当たったらそこに挿入……でいいのかな?
- asuncion
- ベストアンサー率33% (2127/6289)
>「データを挿入するときにソート」したら n個のデータに対して n^2 時間かかるけど, >「データの挿入だけしておいてあとでソート」したら n log n 時間ですむから速いよね>#1. まあ、5件くらいのデータだからいいじゃないですか。
- Tacosan
- ベストアンサー率23% (3656/15482)
「データを挿入するときにソート」したら n個のデータに対して n^2 時間かかるけど, 「データの挿入だけしておいてあとでソート」したら n log n 時間ですむから速いよね>#1. さておき, このプログラムじゃダメダメですよ. sort_up でやってることって, しょせん「バブルソートの 1パス分」だけだもの. 手を動かして紙の上で実際にやってみましたか? あと, sort_up の second_head = (struct ans *)malloc(sizeof(struct ans)); って何の意味があるの? その直後で second_head に代入してるから, これは結局システムを圧迫するためだけだよね? ソートアルゴリズムなんかいっくらでもあるから, そのうち「リストに適切」なものをちゃんと調べて実装すればいいんだけどなぁ.
- asuncion
- ベストアンサー率33% (2127/6289)
>両端にNULLを置いてしまったらsort_up関数内の > if( head->next == NULL )に引っかかってしまいそうな気もする 何をおっしゃっているのか、さっぱりわかりません。 双方向リストといってもいろんな考え方がありますが、 よくありそうなのは下記のとおりです。どこにも矛盾はないはずです。 先頭データ(仮に左端とします)のnextポインタ:左から2番目のデータを指す 先頭データのprevポインタ:NULL(先頭の左側にはデータがない) 最後尾(右端)データのnextポインタ:NULL(最後尾の右側にはデータがない) 最後尾データのprevポインタ:右から2番目のデータを指す
- asuncion
- ベストアンサー率33% (2127/6289)
そもそも、リスト構造は、構築した「後で」ソートするには あまり向いていないデータ構造です。 データをリストに「挿入する」ときにソートするようにすれば、 すべてのデータを挿入した時点でソート済みのリストができあがっています。 逆順のソートがしたければ、双方向リストを作ればよいでしょう。
お礼
なるほど!確かに前のdataも見れるならうまくいきそうです。その場合前を見る(struct ans *prev)とするなら、(struct ans *next)をsort_up関数内で使った式でそのまま流用しても大丈夫でしょうか?
補足
考え方はわかりましたが、自分は双方向リストを使ったことがないので何とも…。両端にNULLを置いてしまったらsort_up関数内の if( head->next == NULL )に引っかかってしまいそうな気もするんですが…
お礼
ありがとうございます。やはり双方向リストを使わなければ無理なようですね。勉強して再チャレンジしてみたいと思います。