質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

アルゴリズム

アルゴリズムとは、定められた目的を達成するために、プログラムの理論的な動作を定義するものです。

連結リスト

連結リストとは、データ構造のひとつであるリストの中で、要素が前後の要素の情報を持つことで、要素が連結(リンク)しているリストの事を呼びます。

コードレビュー

コードレビューは、ソフトウェア開発の一工程で、 ソースコードの検査を行い、開発工程で見過ごされた誤りを検出する事で、 ソフトウェア品質を高めるためのものです。

Q&A

解決済

1回答

1389閲覧

子ノードを生成してリストを編集する

grape_ll

総合スコア83

C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

アルゴリズム

アルゴリズムとは、定められた目的を達成するために、プログラムの理論的な動作を定義するものです。

連結リスト

連結リストとは、データ構造のひとつであるリストの中で、要素が前後の要素の情報を持つことで、要素が連結(リンク)しているリストの事を呼びます。

コードレビュー

コードレビューは、ソフトウェア開発の一工程で、 ソースコードの検査を行い、開発工程で見過ごされた誤りを検出する事で、 ソフトウェア品質を高めるためのものです。

0グッド

0クリップ

投稿2021/06/05 12:57

編集2021/06/05 14:41

###実現したいこと
Step1: 出発のノードnに対し(n null c) をOpenリストに追加する。ただし初めなのでc = h(n) = f(n)
Step2: Openリストからcが最⼩の要素(n p c) を⼀つ選択。nがゴールであれば成功として終了。Openリストが空集合なら失敗として終了。
Step3: ノードnを展開し、⼦ノードの集合を作る。nをCLOSEDリストに追加する。
Step4: ⼦ノードの集合からCLOSEDリストに含まれないノードn’ に対して、(n’ n c’ )をOpenリストに追加する(なお、c’= f(n’) = h(n’) + g(n) + c(n n’),c(n n’) はnからn’へのコストである) である。このときすでに(n’ m c’’ )がOpenリストに⼊っており、c’<c’’ なら新しいものに置き換え、そうでなければOpenリストには追加しない。さらに、CLOSEDリストに含まれるn’ に対して、そのときに探索した(n’ m c’’ ) について、c’ < c’’ならn’をCLOSEDリストから削除し、(n’ n c’ ) をオープンリストに加える。
Step5: Step2へ。

次に具体的な目標が記載されているサイトを記す.
3.ヒューリステック関数の仕様という部分を同じく8パズルにおいて行おうとしている.
参考サイト
###現状のコード
構造体によってopenリストとcloseリストを生成した,
次にリストに要素を加える関数を実現しようとしたが,8パズルの状態を保存するstateの格納が上手くいかない.
プリグラム終了時にリストを破棄する関数を作成した.
ヒューリスティック関数h1を作成した.

###質問内容
・リストに8パズルの状態を格納する方法を教えていただきたい.
.リストの要素を削除するのはリンクを張り替えればよいので,方法としては
子ノードを生成したときにコストを計算し,openリストを一周して最小コストをグローバル関数min_costで取っていく,
その後,もう一度openリストを初めから見ていき,最小コストと一致する状態から子ノードを展開し,
その展開を行ったノードに貼っているリンクを子ノードにつなぎなおす.代わりにcloseリストにそのノードを入れる.
h1()が0となるまでこれを繰り返す.
というように行えばよいのでしょうか.

####残っているやるべきこと
・stateのきちんとした格納.
・木の生成
・リストの要素を削除する機構

木の生成については次のセクションに参考にするコードを載せる,それを参考に作成しようとしている.

C

1#include <stdlib.h> 2#include <stdio.h> 3#include <string.h> 4#include <time.h> 5 6#define TRUE 1 7#define FALSE 0 8#define GOAL 2 9#define SIZE 9 10#define MAX_STATE 181440 11 12typedef struct Olist{ 13 int cost; 14 char state[SIZE]; 15 char parent_state[SIZE]; 16 struct Olist* next; //次の要素のポインタ 17} Olist; 18 19typedef struct Clist{ 20 int cost; 21 char state[SIZE]; 22 char parent_state[SIZE]; 23 struct Olist* next; //次の要素のポインタ 24} Clist; 25 26/* 27* リストを追加する為の関数 28* 第一引数:追加されるリストのポインタ 29* 戻り値:失敗時:NULL, 成功時:リスト 30*/ 31Olist *OlistAdd(Olist* list, int cost, char state[]){ 32 /*メモリの確保*/ 33 Olist* node = (Olist*)malloc(sizeof(Olist)); 34 if(node == NULL) 35 return NULL; 36 37 /*データの追加*/ 38 node->cost = cost; 39 node->state[SIZE] = state[SIZE]; 40 node->next = NULL; 41 42 /*データをリストに追加する*/ 43 if(list == NULL) 44 return node; 45 Olist* search = list; 46 while (search->next != NULL) 47 search = search->next; 48 search->next = node; 49 return list; 50} 51 52Clist *ClistAdd(Clist* list, int cost, char* state, char* parent_state){ 53 /*メモリの確保*/ 54 Clist* node = (Clist*)malloc(sizeof(Clist)); 55 if(node == NULL) 56 return NULL; 57 58 /*データの追加*/ 59 node->cost = cost; 60 node->state = state; 61 node->parent_state = parent_state 62 node->next = NULL; 63 64 /*データをリストに追加する*/ 65 if(list == NULL) 66 return node; 67 Clist* search = list; 68 while (search->next != NULL) 69 search = search->next; 70 search->next = node; 71 return list; 72} 73 74/* 75* リストを削除する為の関数 76* 第一引数:削除するリストのポインタ 77* 戻り値:なし 78*/ 79void OlistAllDelete(Olist* list){ 80 Olist *tmp = list; 81 while (list->next != NULL){ 82 tmp = list->next; 83 list->next = tmp->next; 84 free(tmp); 85 } 86 free(list); 87} 88void ClistAllDelete(Clist* list){ 89 Clist *tmp = list; 90 while (list->next != NULL){ 91 tmp = list->next; 92 list->next = tmp->next; 93 free(tmp); 94 } 95 free(list); 96} 97 98int h1(char state[]){ 99 int count = 0; 100 for(int i = 0;i < 9;i++){ 101 if(state[i] != final_state[i]) count++; 102 } 103 return count; 104} 105 106int min_cost; 107 108char init_state[SIZE] = {8, 6, 7, 2, 5, 4, 3, 0, 1}; 109char final_state[SIZE] = {1, 2, 3, 4, 5, 6, 7, 8, 0}; 110 111void search(){ 112 113} 114 115void main(){ 116 Olist* olist = NULL; 117 Clist* clist = NULL; 118 119 min_cost = h1(init_state); 120 olist = listAdd(olist, h1(init_state), init_state); 121 search(); 122 123 OlistAllDelete(olist); 124 ClistAllDelete(clist); 125 return; 126} 127

###参考コード,およびサイト
コードの仕組みが載っている

C

1#include <stdio.h> 2#include <string.h> 3#include <time.h> 4 5#define TRUE 1 6#define FALSE 0 7#define GOAL 2 8#define SIZE 9 9 10/* 状態数 (9! / 2) */ 11#define MAX_STATE 181440 12 13/* 隣接リスト */ 14const char adjacent[SIZE][5] = { 15 1, 3,-1,-1,-1, 16 0, 4, 2,-1,-1, 17 1, 5,-1,-1,-1, 18 0, 4, 6,-1,-1, 19 1, 3, 5, 7,-1, 20 2, 4, 8,-1,-1, 21 3, 7,-1,-1,-1, 22 4, 6, 8,-1,-1, 23 5, 7,-1,-1,-1, 24}; 25 26/* キュー */ 27char state[MAX_STATE + 1][SIZE]; // +1 はワーク領域 28char space_postion[MAX_STATE]; 29int prev_state[MAX_STATE]; 30 31/* 同一局面チェックテーブル */ 32char check_table[MAX_STATE * 2]; 33 34char init_state[SIZE] = {8, 6, 7, 2, 5, 4, 3, 0, 1}; 35char final_state[SIZE] = {1, 2, 3, 4, 5, 6, 7, 8, 0}; 36 37int h1(char state[]){ 38 int count = 0; 39 for(int i = 0;i < 9;i++){ 40 if(state[i] != final_state[i]) count++; 41 } 42 return count; 43} 44 45 46 47/* 結果を出力 */ 48void print_answer(int n){ 49 int i, j; 50 if( n != 0 ) print_answer( prev_state[n] ); //再帰で最初から描いていく 51 for( i = 0; i < 3; i++ ){ 52 for( j = 0; j < 3; j++ ){ 53 printf("%d ", state[n][i * 3 + j] ); 54 } 55 printf("\n"); 56 } 57 printf("\n"); 58} 59 60/* 番号に変換 */ 61int change_number( char *board ){ 62 char work[SIZE]; 63 static int fact_table[SIZE] = {40320, 5040, 720, 120, 24, 6, 2, 1, 0,}; 64 int j, k, value = 0; 65 memcpy( work, board, SIZE ); 66 for( j = 0; j < SIZE - 1; j++ ){ 67 value += fact_table[j] * work[j]; 68 for( k = j + 1; k < SIZE; k++ ){ 69 if( work[j] < work[k] ) work[k]--; 70 } 71 } 72 //printf("value:%d\n",value); 73 return value; 74} 75 76/* 探索 */ 77void search( void ){ 78 int front = 0, rear = 1; //rearは深さを示す 79 /* 初期化 */ 80 memcpy( state[0], init_state, SIZE ); 81 space_postion[0] = 7; //変更が必要 82 prev_state[0] = -1; 83 check_table[ change_number( init_state ) ] = TRUE; 84 check_table[ change_number( final_state ) ] = GOAL; 85 86 /* キューにデータがある間繰り返す */ 87 while( front < rear ){ 88 int s = space_postion[front]; 89 int i, k, n; 90 for( i = 0; (n = adjacent[s][i]) != -1; i++ ){ 91 /* 前の状態をコピー */ 92 memcpy( state[rear], state[front], SIZE ); 93 /* 移動 */ 94 state[rear][s] = state[rear][n]; //スペースがあった場所にnにあったものを移動 95 state[rear][n] = 0; //nをスペースにする 96 space_postion[rear] = n; //スペースの位置を示す変数にnを格納 97 prev_state[rear] = front; 98 k = change_number( state[rear] ); //状態を番号に変換 99 if( check_table[k] == GOAL ){ //goalの番号を一致したら発見 100 print_answer( rear ); 101 printf("状態数 %d 個\n", rear ); 102 return; 103 } else if( !check_table[k] ){ //なったことがあればすでにTRUE=1が入ってる 104 /* キューに登録 */ 105 check_table[k] = TRUE; 106 rear++; 107 } 108 } 109 110 front++; 111 } 112} 113 114int main(){ 115 /* 116 * 静的変数が 0 に初期化される場合は不用だが 117 * 初期化することは悪いことではない。 118 */ 119 memset( check_table, 0 , MAX_STATE * 2 ); 120 clock_t time = clock(); 121 search(); 122 double result = (double)(clock() - time)/CLOCKS_PER_SEC; 123 printf("%.3fsec \n", result ); 124 return 0; 125}

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

BeatStar

2021/06/05 14:18

「リストボックス」タグは関係ありません。
grape_ll

2021/06/05 14:40

リストと名前があるので,その関連かと思ってしまいました. 修正させていただきます. ご指摘ありがとうございます
guest

回答1

0

ベストアンサー

・リストに8パズルの状態を格納する方法を教えていただきたい.

やりたいのは、こういうことでしょうか。

c

1memcpy(node->state, state, SIZE);

.リストの要素を削除するのはリンクを張り替えればよいので,方法としては
子ノードを生成したときにコストを計算し,openリストを一周して最小コストをグローバル関数min_costで取っていく,
その後,もう一度openリストを初めから見ていき,最小コストと一致する状態から子ノードを展開し,
その展開を行ったノードに貼っているリンクを子ノードにつなぎなおす.代わりにcloseリストにそのノードを入れる.
h1()が0となるまでこれを繰り返す.
というように行えばよいのでしょうか.

「実現したいこと」の記述内容と比較すると、子ノードがすでにopen,closeリストに含まれている場合の対処が抜けているように見えます。

あと、とりあえず動作させるだけならこちらの実装方針でかまいませんが、
速度のことを考えると、ボトルネックになりそうな処理がいくつもあるので厳しそうです。
(最小コストの探索、子ノードがすでにopen,closeリストに含まれているかどうかの判定)

投稿2021/06/06 01:02

actorbug

総合スコア2224

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

grape_ll

2021/06/06 01:15

memkcpyでコピーできますね,ありがとうございます. 確かに,すでに含まれていることの対処が出来ていませんでした.なにかこの実装方針を改良して最適化するものはありますでしょうか.
actorbug

2021/06/06 01:53

正直なところ、単方向リストを採用している時点で、高速化は厳しいと言わざるを得ません。 実装方針から変えるぐらいしか対処方法を思いつきません。
grape_ll

2021/06/06 02:07

そうなんですね,考えてくださりありがとうございます. 人まずは現在の実装方針で進んでみようと思います. 本質問の内容の本題はstateのコピーでしたので,ここでベストアンサーとさせていただきますが,本コードをもう少し進めた形のものを用いた実装するために段階的に質問させていただこうと思っているので,もしまた教えて戴変える箇所があれば,宜しくお願いいたします.
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問