単方向リストの昇順ソートについて

このQ&Aのポイント
  • 単方向リストの昇順ソートについて質問文を解説します。
  • 単方向リストに値を入れるまでの手順を解説しました。
  • ソートの手順について詳しく解説します。
回答を見る
  • ベストアンサー

単方向リストの昇順ソートについて

単方向リストに値を入れるところまでは何とか切り抜けることができましたが、次はソートにてこずっています。this.value と this.next.valueの値を比べて入れ替えるというところまでは何とか想像つきますが、どうやってソートが完了するまでまわしてあげればいいかが分かりません。 class Chain3{ public static void main(String args[]){ Node start = new Node(Integer.parseInt(args[0])); for(int i = 1; i < args.length; i++){ start.append(Integer.parseInt(args[i])); } start.sort(); } } class Node{ private int value; private Node next; public Node(int value, Node next){ this.value = value; this.next = next; } public Node(int value){ this.value = value; } public Node(){ this.value = 0; this.next = null; } public int getValue(){ return value; } public void setValue(int value){ this.value = value; } public Node getNext(){ return next; } public void setNext(Node n){ this.next = n; } public void append(int v){ if(this.next == null) this.next = new Node(v); else this.next.append(v); } //昇順にソートする public void sort(){ int tmp; /*ここで私はバブルソートで行おうと思っているのだが、どう回数制限していいか分からない*/ if(this.value > this.next.value){ tmp = this.value; this.value = this.next.value; this.next.value = tmp; } this.next.sort(); } }

  • Java
  • 回答数2
  • ありがとう数2

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

  • ベストアンサー
  • anmochi
  • ベストアンサー率65% (1332/2045)
回答No.2

 論理的に考えていこう。プログラムを組む時に、その関数はどんなタスクを実行して、その行までにどんなタスクが完了していなければならないのか。 public void sort(){ if(this.next == null) { // 自分が1番下ならソート完了 return; } this.next.sort(); // 配下のソートが終わるまで待つ(ここで自分の1個下が配下中最も小さな値になる) if(this.value > this.next.value){ // 自分の方がおっきければ int tmp = this.value; // 自分と自分の1個下をスワップする(ここで自分の1個下に配下中に配置されるべき値がはいる) this.value = this.next.value; this.next.value = tmp; this.next.sort(); // もう一度配下をソートし直す必要がある } }  後で試してみれば分かるが、実はこのアルゴリズムはバブルソートよりも効率が悪い。改良は頑張ってくれ。  余談だが、せっかくポインタ数珠繋ぎのリストにしたんだから交換法じゃなくて挿入法の方が良いと思う。それと、値の交換よりもアドレスの交換の方が応用が利くよ。

yukikundesuyo
質問者

お礼

返答遅れてゴメンナサイ。 再帰処理が2行があり、多少処理を追うのに苦労しましたが何とか理解できました。ありがとうございます。

その他の回答 (1)

回答No.1

こんばんは。 よくわかりませんが、単純にNULLになるまで回せばいいような・・・? 回数は可変ですから・・・。 (^^ゞ

yukikundesuyo
質問者

補足

具体的にソースで記述するとどのようになりますか?

関連するQ&A

  • Javaで単方向リスト作成に行き詰まり

    Javaで単方向リストを作成しようとしているのですが、append()で1件目のvalueやnextの値をアクセスするにはどうしたらいいか分かりません。ちなみにmain関数は変更しなくていいようです。 class Chain{ public static void main(String args[]){ //1件目のノードの作成 if(args.length == 0){ System.out.println("パラメータを指定してください"); return; } Node start = new Node(Integer.parseInt(args[0])); //2件目のノード作成 for(int i = 1; i < args.length; i++){ start.append(Integer.parseInt(args[i])); } } } class Node{ //メンバ変数(インスタンス変数) private int value; private Node next; //コンストラクタ public Node(int value, Node next){ this.value = value; this.next = next; } public Node(int value){ this.value = value; } public Node(){ this.value = 0; this.next = null; } //アクセスメソッド(setter, getter) public int getValue(){ return value; } public void setValue(int value){ this.value = value; } public Node getNext(){ return next; } public void setNext(Node n){ this.next = n; } //通常のメソッド //追加する public void append(int v){ Node chain = new Node(); chain.value=chain.getValue(); System.out.println(chain.value); } }

    • ベストアンサー
    • Java
  • 文字列を整数に型変換してソート

    コマンドライン入力で文字列を入力してそれを整数型に変換。そして、それをソートするプログラムを作ってるんですが、なぜかうまくいかず、出力される数字がすべて0になります。 どなたかヘルプおねがいします>< class sort32 { public static void main(String[] args) { System.out.println("------------------------"); int i=0; int j=i+1; int vals[]; vals = new int[args.length]; for(i=0;i>args.length ;i++) { vals[i] = Integer.parseInt(args[i]); } java.util.Arrays.sort(vals); for(int k=0; k<vals.length; k++) System.out.println("<"+vals[k]+">"); } }

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

    双方向リストをバブルソートを用いてソートしたいです。 下記がプログラム(一部)ですが、ソートした後にリスト表示すると 無限ループに陥ります。 どこがいけないのでしょうか。 #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; } } }

  • 昇順ソート

    sort.txtから読み込んだ値を 昇順でソートして出力するにはどうしたらよいでしょうか? #include <stdio.h> #include <stdlib.h> #include <string.h> #include <search.h> /* 比較関数 */ int strcmp_asc(const void *, const void *); int main(void) { FILE *fin, *fout; int i; int length; char s[256], s2[256]; if( (fin=fopen("sort.txt","r"))==NULL) { printf("入力ファイルがオープンできません\n"); exit(EXIT_FAILURE); } if( (fout=fopen("file2.txt","w"))==NULL) { printf("出力ファイルがオープンできません\n"); exit(EXIT_FAILURE); } while(fgets(s, 256, fin) != NULL) { /* 要素数を求める */ length = sizeof(s) / 256; /* 昇順でソート */ qsort(s, length, 256, strcmp_asc); /* memset(s2, NULL, sizeof(s2)); for (i = 0; i < length; i++) { } */ fprintf(fout,"%s\n",s2); } fclose(fin); fclose(fout); return 0; } int strcmp_asc(const void *sa, const void *sb) { return strcmp((char *)sa, (char *)sb); } sort.txt 50 45 35 25 15 10 5 1 32 46 8 7 9 19 18 14 16 13 12 17 11 20 40 30 31 3 2 37 38 36 33 39 34 49 47 48 4 6 44 42 43 41 21 22 26 24 28 29 27 23

  • クイックソートをC++で作りたいのですが・・・

    題の通り、C++でクイックソートを作りたいのですが、以下のコードではセグメンテーションエラーで動きませんでした。partition関数があやしいと思い、色々と試してみたのですが、やはりできなかったので、質問させていただくことにしました。 結果としては、print関数で昇順に表示出来ればいいのですが・・・。 以下のコードのどこをどう変えれば良いのか、ご指摘の方、何卒よろしくお願い致します。 #include <iostream> #include <vector> using namespace std; class Array { private: vector<int> array; public: void insert( int value ){ array.push_back( value ); } int getSize( ){ return (int)array.size( ); } void quick_sort( ){ quick_sort( 0, (int)array.size( ) - 1 ); } void quick_sort( int left, int right ); int partition( int left, int right ); void swap(int *a,int *b){int tmp=*a;*a=*b;*b=tmp;} void print( ); }; // クイックソートにより配列の添字 left ~ right の部分を整列する関数 void Array::quick_sort( int left, int right ) { if ( left >= right ) { return; } int v = partition( left, right ); quick_sort( left, v - 1 ); quick_sort( v + 1, right ); } //この関数を考える // 配列の添字 left ~ right の部分を,pivot の値より小さい要素と,大きい要素に分割し pivot の位置を返す関数 int Array::partition( int left, int right ) { int i=left; //左からの処理位置 int j=right; //右からの処理位置 int pivot=array[(int)(left+right)/2]; //基準 int tmp=0; while(true){ while(array[i]<pivot){i++;} while(array[j]>pivot){j--;} if(i>=j){return i;} tmp=array[i]; array[i]=array[j]; array[j]=tmp; i++; j++; } } // 配列の内容を表示する関数 void Array::print( ) { for ( int i = 0; i < (int)array.size( ); i++ ) { cout << array[i] << " "; } cout << endl; } int main( ) { Array a1; a1.insert( 56 ); a1.insert( 34 ); a1.insert( 57 ); a1.insert( 64 ); a1.insert( 3 ); a1.insert( 87 ); a1.insert( 85 ); a1.insert( 37 ); a1.insert( 21 ); a1.insert( 4 ); a1.insert( 68 ); a1.insert( 62 ); a1.insert( 42 ); a1.insert( 55 ); a1.insert( 63 ); a1.insert( 95 ); a1.insert( 7 ); a1.insert( 32 ); a1.insert( 78 ); a1.insert( 11 ); cout << "要素数: " << a1.getSize( ) << endl; cout << "ソート前: "; a1.print( ); a1.quick_sort( ); // ここで,ソートを行う関数を呼び出す cout << "ソート後: "; a1.print( ); return 0; }

  • C#の連結リストがわかりません。

    最近、C#をちゃんとやろうと思い、勉強のためのコードを見ていたのですが以下の連結リストについてわかりません。わからないところにコメントをつけました。呼び出しメソッドはList.Add(2);です。よろしくお願いいたします。 using System; using System.IO; class Node { public int elem; public Node next; public Node() : this(0, null){}//このメソッドがある意味がわかりません。 public Node(int val, Node next) { this.elem = val; this.next = next;//なぜか最初にnextにデバッグするとnullになりますが2回目デバッグからはNodeになります。そもそもなぜクラスにクラスを代入しているかもわかりません。 } } /// <summary> /// 連結リストクラス /// </summary> class List { public Node head; public List() { head = null; } public void Add(int val) { Node node = new Node(val, this.head); this.head = node; } }

  • javaがわかりません。。。

    単方向リストをjavaで書きなさい。 MyListクラス   メソッドを実装 MyListAppクラス メソッドを実行 MyListに実装するメソッド void insertTail(MyList node):リストの最後へ新規データを追加 void insertHead(MyList node):リストの先頭へ新しいデータを追加 void show():現在のリストを表示する void insert(MyList node):リストの途中へ新規データを挿入 ※データが小さい順に並んでいるとして、新規データも小さい順になるような場所へ挿入できるようにする。 void delete(MyList node):リストからデータを1つ削除 ※指定されたデータを見つけ、最初に見つかったデータを削除できるしょうにする。見つからないときは、何もしない。 void deleteHead():先頭のノードを削除する void deleteTail():最後のノードを削除する という問題を解いています。 class MyList{ int data;     //データ MyList next = null; //次のノードへのポインタ MyList(int data){ //新しいノードの作成 this.data = data; } void insertTail(MyList node){ //リストの最後へ追加 MyList tmp = this; while(tmp.next != null){ tmp = tmp.next; } tmp.next = node; } void insertHead(MyList node){ //リストの先頭へ追加 node.next = this.next; this.next = node; } void insert(int head, MyList node){ //リストの途中へ新規データを挿入 MyList tmp = this; while(tmp != null){ if(tmp.data == head){ break; } tmp = tmp.next; } node.next = tmp.next; tmp.next = node; } void delete(int here, MyList node){ //リストからデータを1つ削除 MyList tmp = this; while(tmp != null){ if(tmp.data == here){ break; } tmp = tmp.next; } node = tmp.next; tmp.next = node.next; node.next = null; } void deleteHead(){ //先頭のノードを削除 MyList tmp = next; this.next = tmp.next; tmp.next = null; } void deleteTail(){ //最後のノードを削除 MyList tmp = this; while(tmp.next != null){ tmp = tmp.next; } tmp = null; } void show(){ MyList tmp = next; while(true){ System.out.print(tmp.data); if(tmp.next == null) break; tmp = tmp.next; } System.out.println(""); } } class MyListApp{ public static void main(String[] args){ MyList list = new MyList(0); //初期ダミー System.out.println("最後に追加"); list.insertTail(new MyList(1)); //最後に追加 list.show(); list.insertTail(new MyList(5)); list.show(); System.out.println(); System.out.println("先頭に追加"); list.insertHead(new MyList(8)); //先頭に追加 list.show(); list.insertHead(new MyList(9)); list.show(); System.out.println(); System.out.println("途中からデータを追加"); list.insert(1, new MyList(2)); //途中からデータの追加 list.show(); list.insert(2, new MyList(3)); list.show(); System.out.println(); System.out.println("リストからデータを削除"); list.delete(8, new MyList(1)); //リストからデータを削除 list.show(); System.out.println(); System.out.println("先頭のノードを削除"); list.deleteHead(); //先頭のノードを削除 list.show(); list.deleteHead(); list.show(); System.out.println(); System.out.println("最後のノードを削除"); list.deleteTail(); //最後のノードを削除 list.show(); list.deleteTail(); list.show(); } } ここまではできたのですが、どうしても最後のノード削除ができません。 どうしたらいいでしょうか。

    • ベストアンサー
    • Java
  • intではなくStringで・・・

    こんなソースがあります。。 public class Check { public static void main(String[] args) { int i = Integer.parseInt(args[0]); if (i == 123) { System.out.println("あたり!"); } else if (i < 123) { System.out.println("はずれ!"); } else { System.out.println("おおはずれ!"); } } } これを、int型の文字を入力して判定させるのではなく、String型の文字で判定させたいのですが、 int i = Integer.parseInt(args[0]);をどう変えればいけるでしょうか? よろしくお願いします!

    • ベストアンサー
    • Java
  • java教えてください。

    双方向リストをjavaで書きたいんですけどここまで書いて双方向リストになってるか不安になってきました。 これは双方向リストになっていますか? class MyListw{ int data; MyListw next = null; //次のノードへのポインタ MyListw prev = null; //前のノードへのポインタ MyListw(int data){ this.data = data; } void insertTail(MyListw node){ //リストの最後へ追加 MyListw tmp = this; while(tmp.next != null){ tmp = tmp.next; } tmp.next = node; node.prev = tmp.next; } void insertHead(MyListw node){ //リストの先頭へ追加 node.next = this.next; this.next = node; node.prev = this.next; } void insert(int head, MyListw node){ //リストの途中へ新規データを挿入 MyListw tmp = this; while(tmp != null){ if(tmp.data == head){ break; } tmp = tmp.next; } node.next = tmp.next; tmp.next = node; node.prev = tmp.next; } void delete(int here, MyListw node){ //リストからデータを1つ削除 MyListw tmp = this; while(tmp != null){ if(tmp.data == here){ break; } tmp = tmp.next; } node = tmp.next; tmp.next.prev = node; tmp.next = node.next; node.next.prev = tmp.next; node.next = null; node.prev = null; } void deleteHead(){ //先頭のノードを削除 MyListw tmp = next; this.next = tmp.next; tmp.next.prev = this.next; tmp.next = null; tmp.prev = null; } void deleteTail(){ //最後のノードを削除 MyListw tmp = this; MyListw lastList = null; while(tmp.next != null){ lastList = tmp; tmp = tmp.next; } lastList.next = null; lastList.prev = null; } void show(){ MyListw tmp = next; while(true){ System.out.print(tmp.data); if(tmp.next == null) break; tmp = tmp.next; } System.out.println(""); } void showTail(){ } } class MyListwApp{ public static void main(String[] args){ MyListw list = new MyListw(0); //初期ダミー System.out.println("最後に追加"); list.insertTail(new MyListw(1)); list.show(); System.out.println("逆順に表示"); list.showTail(); System.out.println("\n"); list.insertTail(new MyListw(5)); list.show(); System.out.println("逆順に表示"); list.showTail(); System.out.println("先頭に追加"); list.insertHead(new MyListw(8)); list.show(); System.out.println("逆順に表示"); list.showTail(); System.out.println("\n"); list.insertHead(new MyListw(9)); list.show(); System.out.println("逆順に表示"); list.showTail(); System.out.println("途中からデータを追加"); list.insert(1, new MyListw(2)); list.show(); System.out.println("逆順に表示"); list.showTail(); System.out.println("\n"); list.insert(2, new MyListw(3)); list.show(); System.out.println("逆順に表示"); list.showTail(); System.out.println("リストからデータを削除"); list.delete(8, new MyListw(1)); list.show(); System.out.println("逆順に表示"); list.showTail(); System.out.println("先頭のノードを削除"); list.deleteHead(); //先頭のノードを削除 list.show(); System.out.println("逆順に表示"); list.showTail(); System.out.println("\n"); list.deleteHead(); list.show(); System.out.println("逆順に表示"); list.showTail(); System.out.println("最後のノードを削除"); list.deleteTail(); //最後のノードを削除 list.show(); System.out.println("逆順に表示"); list.showTail(); System.out.println("\n"); list.deleteTail(); list.show(); System.out.println("逆順に表示"); list.showTail(); } }

    • ベストアンサー
    • Java
  • クイックソートの交換回数

    クイックソートを行うプログラムを書いています。 これを、比較回数と交換回数を表示できるように改良したいのですが、うまくいきません。カウントする場所は間違えてないと思うのですが、出力の場所が悪いせいか、大量の出力結果が表示されます。 うまく表示させる方法を教えてください。 ~time.c~ #include <stdio.h> #include <stdlib.h> #include <time.h> #include "sfmt.h" #define MAX 5000 void quick_sort(int a[], int start, int end); main() { int i , x[MAX] , n; time_t start , end ; int sn; printf("適当な数字の入力 : "); scanf("%d", sn); init_gen_rand(sn); for(i=0; i<MAX; i++) x[i]= (gen_rand32()% MAX);; n=MAX; start = clock(); //測定対象プログラム quick_sort(x, 0, n-1); end = clock(); printf("sort\n"); for(i =0 ; i < n ; i++ ) if ( i == i/100*100) printf("%d\n" , x[i]); printf ("実行時間: %f sec\n" , (double)(end-start) /CLOCKS_PER_SEC); return 0; } ~quick.c~ #include <stdio.h> int hikaku = 0, koukan = 0; int divide_array(int x[], int start, int end) { int i, j, tmp; i = start; j = end -1; while(1){ while(x[i] < x[end])i++; hikaku++; //比較カウント while(x[j] > x[end] && j>i)j--; hikaku++; //比較カウント if(i >= j) break; tmp = x[i]; x[i] = x[j]; x[j] = tmp; koukan++; //交換カウント i++; j--; } tmp = x[i]; x[i] = x[end]; x[end] = tmp; printf("比較回数: %d\n", hikaku); printf("交換回数: %d\n", koukan); return i; } ~quick2.c~ int divide_array(int x[], int start, int end); void quick_sort(int a[], int start, int end); void quick_sort(int a[], int start, int end) { int s; if(start >= end) return; s = divide_array(a, start, end); quick_sort(a, start, s-1); quick_sort(a, s+1, end); }

専門家に質問してみよう