掲示板利用宣言

 次のフォームをすべてチェックしてからご利用ください。

 私は

 題名と投稿者名は具体的に書きます。
 課題の丸投げはしません。
 ソースの添付は「HTML変換ツール」で字下げします。
 返信の引用は最小限にします。
 環境(OSとコンパイラ)や症状は具体的に詳しく書きます。
 返信の付いた投稿は削除しません。
 マルチポスト(多重投稿)はしません。

掲示板2

管理者用メニュー    ツリーに戻る    携帯用URL    ホームページ    ログ    タグ一覧

No.27369

双方向リストのソート
投稿者---コジーニョ(2006/06/27 21:34:34)


現在C言語の勉強中なのですが、困っています。
実行モジュール引数としまして3が選択されたときに
まず読み込まれた順にファイルを出力し、
その後に郵便番号昇順ソートで出力するという処理を
行いたいのですが、最後のソートがうまくいきません。。。
ソートを行うためのfor文がうまく考えられないのと、
双方向リストでの繋ぎ変えがうまくいっていないと思うのですが。。。

以下、ソースです。

#include <stdio.h>
#include <stdlib.h>

#define MAX_CHAR 256
#define FALSE 1
#define TRUE 0
#define NAME 20
#define ADD 5
#define LINE 10

/*構造体の宣言*/
struct list{
char name[NAME]; /*名前メンバ*/
char sex; /*性別メンバ*/
int add; /*郵便番号メンバ*/
struct list *next; /*次の構造体のアドレス*/
struct list *before; /*前の構造体のアドレス*/
};

int main(int argc, char *argv[])
{
struct list person; /*構造体配列の宣言*/
struct list *head; /*最初の構造体のアドレス用ポインタ(ダミー用)*/
struct list *wp; /*構造体作業用ポインタ*/
struct list *wkdata; /*データ設定用ポインタ*/
FILE *fin,*fout,*fout1,*fout2; /*入出力用ファイルポインタ*/
char str[MAX_CHAR]; /*ファイル読み込み用文字列*/
char add[ADD]; /*郵便番号代入用文字列*/
char *temp; /*作業用ポインタ*/
int n; /*文字列用変数*/
int cc; /*文字カウント用変数*/
int cmdline; /*実行モジュール引数用変数*/
int cnt=0; /*行カウント用変数*/
int word; /*単語カウント用変数*/
int data,sort;

/*引数の個数チェックをする*/
if(argc != 2){
fprintf(stderr,"引数の個数が違います。\n");
return FALSE;
}

/*文字列を数値にする*/
cmdline = atoi(argv[1]);

/*最初の構造体の場所を記憶する*/
head = &person;
/*最初はデータがないのでNULLを設定しておく*/
head->next = NULL;
head->before = NULL;

/*ファイルオープン処理*/
/*実行モジュール引数として1か2が選択されたとき*/
if(cmdline == 1 || cmdline == 2){
/*入力ファイルオープンに失敗したときの処理*/
if((fin=fopen("SV.ADR","r"))==NULL){
fprintf(stderr,"入力ファイルオープンに失敗しました。\n");
return FALSE;
}

/*出力ファイルオープンに失敗したときの処理*/
if((fout=fopen("ADR.SV","w"))==NULL){
fprintf(stderr,"出力ファイルオープンに失敗しました。\n");
fclose(fin);
return FALSE;
}
}
/*実行モジュール引数として3が選択されたとき*/
else if(cmdline == 3){
if((fin=fopen("SV.ADR","r"))==NULL){
fprintf(stderr,"入力ファイルオープンに失敗しました。\n");
return FALSE;
}

if((fout1=fopen("ADR.SV1","w"))==NULL){
fprintf(stderr,"出力ファイルADR.SV1のオープンに失敗しました。\n");
fclose(fin);
return FALSE;
}

if((fout2=fopen("ADR.SV2","w"))==NULL){
fprintf(stderr,"出力ファイルADR.SV2のオープンに失敗しました。\n");
fclose(fin);
fclose(fout2);
return FALSE;
}
}
/*1、2、3以外の値が入力されたとき*/
else{
fprintf(stderr,"入力された値が不正です。処理を終了します。\n");
return FALSE;
}

つづく


この投稿にコメントする

削除パスワード

発言に関する情報 題名 投稿番号 投稿者名 投稿日時
<子記事> Re:双方向リストのソート 27370 コジーニョ 2006/06/27 21:35:55


No.27370

Re:双方向リストのソート
投稿者---コジーニョ(2006/06/27 21:35:55)


/*1行処理。ファイルの終わりまで*/
while((fgets(str,MAX_CHAR,fin))!=NULL){

/*構造体1個分のメモリを確保する*/
/*構造体1個分のメモリ確保に失敗した場合の処理も*/
if((wkdata = (struct list*)malloc(sizeof(struct list)))==NULL){
fprintf(stderr,"メモリ確保できません。\n");
fclose(fin);
fclose(fout);
return FALSE;
}

/*単語カウント&文字カウントリセット*/
word=0;
cc=0;
/*ポインタに名前メンバのアドレスを代入*/
temp = wkdata->name;

/*一文字処理。行の終わりまで*/
for(n=0; str[n]!='\0'; n++){
/*文字または数字が来た場合の処理*/
if((str[n]>='A' && str[n]<='z') || (str[n]>='0' && str[n]<='9')){
/*ポインタに文字列を代入*/
*temp = str[n];
/*ポインタの番地を進める*/
temp++;
/*文字カウントアップ*/
cc++;

/*区切り文字が来た場合の処理*/
if(str[n+1]==' '||str[n+1]=='\n'||str[n+1]=='\t'){
/*終端文字を代入*/
*temp = '\0';
/*単語カウントアップ*/
word++;
/*文字カウントリセット*/
cc=0;

/*単語カウントごとの場合わけ*/
/*単語カウントが1ならば、性別メンバのアドレスを代入*/
if(word == 1){
temp = &wkdata->sex;
/*単語カウントが2ならば、郵便番号メンバのアドレスを代入*/
}else if(word == 2){
temp = add;
}
}
}
}
/*char型をint型に変換*/
wkdata->add = atoi(add);

for(wp=head; wp->next != NULL; wp = wp->next){
/*コマンドラインから1が入力された場合*/
if(cmdline == 1){
/*構造体の郵便番号メンバより小さかったなら*/
if(wkdata->add < wp->next->add){
/*チェインをつなぎかえる*/
wkdata->next = wp->next;
wp->next->before = wkdata;
wkdata->before = wp;
wp->next = wkdata;
break;
}
}
/*コマンドラインから2が入力された場合*/
else if(cmdline == 2){
/*構造体の郵便番号メンバより大きかったなら*/
if(wkdata->add > wp->next->add){
/*チェインをつなぎかえる*/
wkdata->next = wp->next;
wp->next->before = wkdata;
wkdata->before = wp;
wp->next = wkdata;
break;
}
}
}

if(wp->before == NULL){
wkdata->before = NULL;
wp->before = wkdata;
}

if(wp->next == NULL){
wkdata->next = NULL;
wp->next = wkdata;
}

/*行数のカウント*/
cnt++;
}

/*ファイル出力*/
if(cmdline == 1 || cmdline == 2){
for(wp = head->next; wp != NULL; wp = wp->next){
fprintf(stdout,"%-10d%-20s%-20c\n",wp->add,wp->name,wp->sex);
}
fclose(fin);
fclose(fout);
}
else if(cmdline == 3){
for(wp = head->next; wp != NULL; wp = wp->next){
fprintf(fout1,"%-10d%-20s%-20c\n",wp->add,wp->name,wp->sex);
}
fclose(fout1);
for(sort=0; sort<cnt; sort++){
for(wp = head->next; wp != NULL; wp = wp->next){
if(wp->add < wp->next->add){
wp->next->before = wp->before;
wp->before = wp->next;
wp->before->next = wp->next;
wp->next = wp->next->next;
wp->next->next = wp;
wp->next->next->before = wp;
}
}
}
for(wp = head->next; wp != NULL; wp = wp->next){
fprintf(stdout,"%-10d%-20s%-20c\n",wp->add,wp->name,wp->sex);
}

fclose(fin);
fclose(fout2);
}

return TRUE;
}

このような感じです。
お忙しいとは思いますが、ヒントなどでもいただけると嬉しいです!
よろしくお願いいたしますm(__)m


この投稿にコメントする

削除パスワード

No.27371

Re:双方向リストのソート
投稿者---επιστημη(2006/06/27 21:46:47)


>お忙しいとは思いますが、ヒントなどでもいただけると嬉しいです!
>よろしくお願いいたしますm(__)m

# 本筋の解決策ではないのは承知の上で

struct record {
 char name[NAME]; /*名前メンバ*/
 char sex; /*性別メンバ*/
 int add; /*郵便番号メンバ*/
};

struct list{
 struct record* data;
 struct list *next; /*次の構造体のアドレス*/
 struct list *before; /*前の構造体のアドレス*/
};

としておいて、
入れ替えの際に(繋ぎ換えずに)dataだけを"交換"する。



この投稿にコメントする

削除パスワード

No.27375

Re:双方向リストのソート
投稿者---コジーニョ(2006/06/27 23:17:23)


>>お忙しいとは思いますが、ヒントなどでもいただけると嬉しいです!
>>よろしくお願いいたしますm(__)m
>
># 本筋の解決策ではないのは承知の上で
>
>struct record {
> char name[NAME]; /*名前メンバ*/
> char sex; /*性別メンバ*/
> int add; /*郵便番号メンバ*/
>};
>
>struct list{
> struct record* data;
> struct list *next; /*次の構造体のアドレス*/
> struct list *before; /*前の構造体のアドレス*/
>};
>
>としておいて、
>入れ替えの際に(繋ぎ換えずに)dataだけを"交換"する。

はー・・・そんな方法もあるのですね!
一応自分なりに考えた方法をもう一つ。

モジュール引数として3が選択されたときには、
もう一つポインタを用意してあげて
そのまま出力と、繋ぎ変えて出力とっていう方法も
考えたのですが。。。
変数多くなっちゃうからやめたほうがいいのかな〜とも思いまして^^;

これからこいつを処理別に関数化しようと思ってるのですが、
そうしたら変数宣言もっとスマートになりますかね。。。?



この投稿にコメントする

削除パスワード

No.27378

Re:双方向リストのソート
投稿者---επιστημη(2006/06/27 23:32:23)


>モジュール引数として3が選択されたときには、
>もう一つポインタを用意してあげて
>そのまま出力と、繋ぎ変えて出力とっていう方法も
>考えたのですが。。。
>変数多くなっちゃうからやめたほうがいいのかな〜とも思いまして^^;
>
>これからこいつを処理別に関数化しようと思ってるのですが、
>そうしたら変数宣言もっとスマートになりますかね。。。?

どちらも「やってみればいい」
# いずれにせよ、今のままじゃはっきり申し上げて"汚い"と感じます。



この投稿にコメントする

削除パスワード

No.27410

Re:双方向リストのソート
投稿者---コジーニョ(2006/06/29 00:59:36)


やってみました。
双方向ではなく、単方向リストになりましたが・・・。
以下ソースです。
挿入ソートでソートしてます。
コンパイルは通るのですが、出力段階でコアダンプしちゃいます;;
#include <stdio.h>
#include <stdlib.h>

#define MAX_CHAR 256 
#define FALSE      1 
#define TRUE       0 
#define NAME      20
#define ADD        5
#define LINE      10

/*構造体の宣言*/
struct list{
  char name[NAME];              /*名前メンバ*/
  char sex;                     /*性別メンバ*/
  int add;                      /*郵便番号メンバ*/
  struct list *next;            /*次の構造体のアドレス*/
};

int main(int argc, char *argv[])
{
  struct list person;                /*構造体配列の宣言*/
  struct list *head;                 /*最初の構造体のアドレス用ポインタ(ダミー用)*/
  struct list *wp;                   /*構造体作業用ポインタ*/
  struct list *wkdata;               /*データ設定用ポインタ*/
  struct list *tmp,*base;
  FILE *fin,*fout,*fout1,*fout2;     /*入出力用ファイルポインタ*/
  char str[MAX_CHAR];                /*ファイル読み込み用文字列*/
  char add[ADD];                     /*郵便番号代入用文字列*/
  char *temp;                        /*作業用ポインタ*/
  int n;                             /*文字列用変数*/
  int cc;                            /*文字カウント用変数*/
  int cmdline;                       /*実行モジュール引数用変数*/ 
  int cnt=0;                         /*行カウント用変数*/
  int word;                          /*単語カウント用変数*/
  int sort;

  /*引数の個数チェックをする*/
  if(argc != 2){
    fprintf(stderr,"引数の個数が違います。\n");
    return FALSE;
  }

  /*文字列を数値にする*/
  cmdline = atoi(argv[1]);

  /*最初の構造体の場所を記憶する*/
  head = &person;
  /*最初はデータがないのでNULLを設定しておく*/
  head->next = NULL;

  /*ファイルオープン処理*/
  〜省略〜

  /*1行処理。ファイルの終わりまで*/
  while((fgets(str,MAX_CHAR,fin))!=NULL){

    /*構造体1個分のメモリを確保する*/
    /*構造体1個分のメモリ確保に失敗した場合の処理も*/
    if((wkdata = (struct list*)malloc(sizeof(struct list)))==NULL){
         fprintf(stderr,"メモリ確保できません。\n");
         fclose(fin);
         fclose(fout);
         return FALSE;
    }

    /*単語カウント&文字カウントリセット*/
    word=0;
    cc=0;
    /*ポインタに名前メンバのアドレスを代入*/
    temp = wkdata->name;

    /*一文字処理。行の終わりまで*/
    for(n=0; str[n]!='\0'; n++){
        /*文字または数字が来た場合の処理*/
        if((str[n]>='A' && str[n]<='z') || (str[n]>='0' && str[n]<='9')){   
        /*ポインタに文字列を代入*/
        *temp = str[n];
        /*ポインタの番地を進める*/
        temp++;
        /*文字カウントアップ*/
        cc++;

        /*区切り文字が来た場合の処理*/
        if(str[n+1]==' '||str[n+1]=='\n'||str[n+1]=='\t'){
            /*終端文字を代入*/
            *temp = '\0';
            /*単語カウントアップ*/
            word++;
            /*文字カウントリセット*/
            cc=0;
        
            /*単語カウントごとの場合わけ*/
            /*単語カウントが1ならば、性別メンバのアドレスを代入*/
            if(word == 1){
                temp = &wkdata->sex;
            /*単語カウントが2ならば、郵便番号メンバのアドレスを代入*/
            }else if(word == 2){
                temp = add;
            }
        }
        }
    }
    /*char型をint型に変換*/
    wkdata->add = atoi(add);

    for(wp=head; wp->next != NULL; wp = wp->next){
        /*コマンドラインから1が入力された場合*/
        if(cmdline == 1){
        /*構造体の郵便番号メンバより小さかったなら*/
            if(wkdata->add < wp->next->add){
            /*チェインをつなぎかえる*/
            wkdata->next = wp->next;
            wp->next = wkdata;
            break;
        }
        }
        /*コマンドラインから2が入力された場合*/
        else if(cmdline == 2){
        /*構造体の郵便番号メンバより大きかったなら*/
        if(wkdata->add > wp->next->add){
            /*チェインをつなぎかえる*/
            wkdata->next = wp->next;
            wp->next = wkdata;
            break;
        }
        }
    }

    if(wp->next == NULL){
        wkdata->next = NULL;
        wp->next = wkdata;
    }   

    /*行数のカウント*/
    cnt++;
  }

  /*ファイル出力*/
  if(cmdline == 1 || cmdline == 2){
     for(wp = head->next; wp != NULL; wp = wp->next){
    fprintf(stdout,"%-10d%-20s%-20c\n",wp->add,wp->name,wp->sex);
     }
  fclose(fin);
  fclose(fout);
  }
  else if(cmdline == 3){
     for(wp = head->next; wp != NULL; wp = wp->next){
    fprintf(fout1,"%-10d%-20s%-20c\n",wp->add,wp->name,wp->sex);
     }
     fclose(fout1);
     for( ;head->next != NULL; head = head->next){
        for(wp = head->next; wp->next != NULL; wp = wp->next){
           if(head->next->add > wp->next->add){
             tmp = wp->next->next;
             wp->next->next = head->next;
             head->next = wp->next;
             wp->next = tmp;
           }
        }
     }
     for(wp = head->next; wp != NULL; wp = wp->next){
      fprintf(stdout,"%-10d%-20s%-20c\n",wp->add,wp->name,wp->sex);
     }
  fclose(fin);
  fclose(fout2);
  } 

  return TRUE;
}



おかしい点あったら指摘していただけるとありがたいです(´□`;)


この投稿にコメントする

削除パスワード

No.27411

Re:双方向リストのソート
投稿者---acid(2006/06/29 09:39:02)


見づらいソースの典型のようなソースですね…

まず一番の問題として、関数分けがされていません。
妙に変数が多いのはそのせいですね。
全部mainに書かないで、ファイルオープン、ソート、出力という風に機能ごとに関数わけをしましょう。
目安は一関数50行位です。

それと処理の重複が非常に多いです。
入力ファイルオープン何かは、二つ書いてありますが全く同じ処理ですね。
fcloseも色々なところで呼ばれてますが、本来はソース中に一度だけ呼べばいいはずです。
出力も似たような処理が並んでます。もっと簡潔に出来るはずです。
これらは関数分けをすることで、大方解決できるはずです。

変数ccとcntは使われてすらいません。
使わない変数はいりません。

ところで読み込んでいるファイルは、どういうファイルなのでしょう。
検証したくても仕様が分からないので出来ません。

ちなみにgccではコアダンプは起こりませんでした。
適当にファイルを書いたので、あっているかどうかの検証は出来ません


この投稿にコメントする

削除パスワード

No.27412

Re:双方向リストのソート
投稿者---コジーニョ(2006/06/29 10:00:58)


関数化はこれから行っていこうと思っています。
読み込んでいるファイル内容は

Takeuti  M  180
Morita  M  203
Fujita  M  187
Wakamatsu    F  190
Sato  F  164
Matsufuji  M  133

こんな感じで

名前 性別 郵便番号

といった感じのものを読み込んでいます。

今もソートの開始、終了条件のあたりでコアダンプしているのではと
思っていじっているのですが。。。




この投稿にコメントする

削除パスワード

No.27444

Re:双方向リストのソート
投稿者---コジーニョ(2006/06/29 21:30:19)


あれから開始条件、終了条件を自分なりに考えて、
ようやくそれなりにソートされるものができました。

一応動くのですが、問題がありまして。。。

同じ数字が来るときに、なぜかうまくソートができません;;

確かめるために、データが10個あるのですが、そのうちの4個を

同じ数字に変更したファイルを読み込んだところ、やはりうまくうごきませんでした。

以下、問題のソート部分です。

 else if(cmdline == 3){
     base = head;
     for(wp = head->next; wp != NULL; wp = wp->next){
    fprintf(fout1,"%-10d%-20s%-20c\n",wp->add,wp->name,wp->sex);
     }
     fclose(fout1);

   for(;head->next != NULL; head = head->next){
    ++i;
    for(wp = head->next; wp->next != NULL; wp = wp->next){
        if(head->next->add > wp->next->add){
        tmp = wp->next->next;
        wp->next->next = head->next;
        head->next = wp->next;
        wp->next = tmp;
        if(wp->next->next ==NULL){
            wp->next->next = head->next;
            head->next = wp->next;
            wp->next = NULL;
            break;
        }
        }
    }
    }
     for(wp = base->next; wp != NULL; wp = wp->next){
    fprintf(stdout,"%-10d%-20s%-20c\n",wp->add,wp->name,wp->sex);
     }
  fclose(fin);
  fclose(fout2);
  } 

図に描いてのソートの仕組みはわかっているつもりなのですが。。。

問題点がありましたら、指摘等お願いしたいです。

すっかり環境とOSを書き忘れていたことを、この場を借りて
お詫びいたしますm(__)m

コンパイラはgccでOSはXPのプロフェッショナルです。




この投稿にコメントする

削除パスワード

No.27455

Re:双方向リストのソート
投稿者---かずま(2006/06/30 02:42:45)


コマンドライン引数が 1、2、3 のとき何をやろうとしているのか
よく分からなかったので、勝手に次のように決めてしまいました。

 1: 入力時に昇順にソート
 2: 入力時に降順にソート
 3: 出力前に昇順にソート

本当はどうなんですか?
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

struct list {
    char name[20];
    char sex;
    int  add;
    struct list *next;
};

int main(int argc, char *argv[])
{
    int cmd;   char buf[256];   struct list hd, *np, *wp, *next;

    if (argc != 2) return 1;
    cmd = atoi(argv[1]);
    if (cmd < 1 || cmd > 3) return 1;
    hd.next = NULL;
    while (fgets(buf, sizeof buf, stdin)) {
        if (sscanf(buf, "%s %c%d", hd.name, &hd.sex, &hd.add) != 3) break;
        np = malloc(sizeof *np);
        *np = hd;
        switch (cmd) {
        case 1:
            for (wp = &hd; wp->next && np->add >= wp->next->add; wp = wp->next) ;
            np->next = wp->next; wp->next = np; break;
        case 2:
            for (wp = &hd; wp->next && np->add <= wp->next->add; wp = wp->next) ;
            np->next = wp->next; wp->next = np; break;
        case 3:
            np->next = hd.next;  hd.next = np;  break;
        }
    }
    if (cmd == 3) {
        next = hd.next;  hd.next = NULL;
        while (np = next) {
            next = np->next;
            for (wp = &hd; wp->next && np->add >= wp->next->add; wp = wp->next) ;
            np->next = wp->next;  wp->next = np;
        }
    }
    for (wp = hd.next; wp; wp = wp->next)
        printf("%-10d%-20s%c\n", wp->add, wp->name, wp->sex);
    return 0;
}



この投稿にコメントする

削除パスワード

管理者用メニュー    ツリーに戻る    携帯用URL    ホームページ    ログ    タグ一覧