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

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

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

Objective-Cはオブジェクト指向型のプログラミング言語のひとつです。C言語をベースにSmalltalkが取り入れられています。

C

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

CSV

CSV(Comma-Separated Values)はコンマで区切られた明白なテキスト値のリストです。もしくは、そのフォーマットでひとつ以上のリストを含むファイルを指します。

Q&A

解決済

3回答

2119閲覧

C言語で二次元の点集合について点集合を含む最小の凸多角形(凸包)を構築するプログラムを作成したい

Syoshinsya_1

総合スコア3

Objective-C

Objective-Cはオブジェクト指向型のプログラミング言語のひとつです。C言語をベースにSmalltalkが取り入れられています。

C

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

CSV

CSV(Comma-Separated Values)はコンマで区切られた明白なテキスト値のリストです。もしくは、そのフォーマットでひとつ以上のリストを含むファイルを指します。

0グッド

0クリップ

投稿2022/02/08 09:34

編集2022/02/08 10:24

前提・実現したいこと

 与えられた4つ以上の2次元座標の集合(csvファイル)についてgraham’s scanという方法を用いてすべての点集合を含みかつ凸(凸包)な多角形のの頂点をcsvファイルに書き込む形で出力するプログラムを作成したいです。
プログラム全体の大まかな流れは以下の通りです。
イメージ説明
図1全体の流れ

次に、凸包探索の方法について説明します。
イメージ説明

(c)でソートされた点の集合を小さい番号から検証していきます。
ここでは一般的に点 Pn, Pn+1, Pn+2 について考ると経路 PnPn+1 から見たとき,経路Pn+1Pn+2 が直進または時計回り (clockwise) の曲り道になる場合と,反時計回り (counter clockwise) の曲り道になる場合が存在します。前者の場合,点 Pn+1 は凸包内部の点(頂点になりえない点)であるため,Pn+1をリストから削除し,Pn−1, Pn, Pn+1(元は Pn+2 だった点) について同様の処理を行います。Pn+1, Pn+2, Pn+3 について処理を行う。後者の場合、Pn+1, Pn+2, Pn+3について同様の処理を行います。この作業を繰り返し凸包を計算します。

発生している問題・エラーメッセージ

コンパイルはできたものの実行するとmain関数内のリスト構造を選択ソートする際のプログラム、void sortlist(void) が動作しておらずコードを見直したがどこが間違えているのか分からなかった。

./a.out input ok find bottom ok. pos=(0.000000,0.000000) swapnode ok 0.000000,0.000000 0.500000,1.400000 1.000000,1.000000 -0.500000,1.500000 2.000000,2.000000 0.000000,1.000000 1.000000,0.000000 0.800000,0.300000 0x7fffbd56b6f0, 0x7fffbd56b6f0, 1 ^Z

該当のソースコード

C

1#include <math.h> 2#include <stdio.h> 3#include <stdlib.h> 4#include <time.h> 5 6typedef struct { //座標の構造体 7 8 double x, y; 9} point; 10 11typedef struct node { 12 point data; 13 struct node *next; 14 struct node *pre; 15} node; 16 17node root = {{0,0}, NULL, NULL}; 18 19int addNode(point a) { 20 // リストの末尾要素の次は常にNULLになるように設計してある。 21 node *c; 22 node *newNode = (node *)malloc(sizeof(node)); 23 if (newNode == NULL) { 24 printf("メモリの確保に失敗しました\n"); 25 exit(1); 26 } 27 newNode->data = a; 28 c = &root; 29 while (c->next) c = c->next; 30 31 newNode->next = NULL; 32 newNode->pre = c; 33 c->next = newNode; 34 return 1; 35} 36 37node *find_bottom(void) { 38 node *min = root.next; 39 for (node *n = root.next->next; n; n = n->next) { 40 if ((n->data.y < min->data.y) || (min->data.y == n->data.y && n->data.x < min->data.x)) { 41 // yが最小、またはyが同じ場合よりxが小さい方を抽出 42 min = n; 43 } 44 } 45 return min; 46} 47 48int delete_node(int num) { 49 50 if (num < 1) return 0; 51 52 int pos = 1; 53 node *preNode = &root; /* root は0番目のノード */ 54 node *delete_target; 55 56 while (pos < num) { 57 if (preNode == NULL) { 58 return 0; 59 } 60 preNode = preNode->next; 61 pos++; 62 } 63 delete_target = preNode->next; 64 preNode->next = delete_target->next; 65 66 if (delete_target->next != &root) 67 delete_target->next->pre = preNode; 68 69 free(delete_target); 70 return 1; 71} 72 73//角度を求める 74double theta(node *point1, node *point2) { 75 double dx = point2->data.x - point1->data.x; 76 double dy = point2->data.y - point1->data.y; 77 return atan2(dy, dx); 78} 79//距離を求める 80double distance(point a, point b) { 81 double x = a.x - b.x; 82 double y = a.y - b.y; 83 x = x * x; 84 y = y * y; 85 return x + y; 86} 87//時計回りかどうかを判定 88float checkclockwise(node *point1, node *point2, node *point3) { 89 return (point2->data.x - point1->data.x) * (point3->data.y - point2->data.y) -//y->x 90 (point2->data.y - point1->data.y) * (point3->data.x - point2->data.x); 91} 92 93void delete_theta(void) { 94 node *min = root.next, *n = min->next; 95 96 for (int i = 2; n->next != &root; i++) { 97 //同じ角度だったら 98 if (theta(min, n) == theta(min, n->next)) { 99 //基準から近い方を消す 100 if (distance(min->data, n->data) > distance(min->data, n->data)) { 101 delete_node(i + 1); 102 i--; 103 } else { 104 n = n->next; 105 delete_node(i); 106 i--; 107 } 108 } else { 109 n = n->next; 110 } 111 } 112} 113 114int swapNode(node *n1, node *n2) { 115 node *tmp; 116 if (n1 == NULL || n2 == NULL) { 117 printf("n1 or n2 is NULL\n"); 118 exit(1); 119 } 120 121 n1->pre->next = n2; 122 n2->pre->next = n1; 123 124 tmp = n1->pre; 125 n1->pre = n2->pre; 126 n2->pre = tmp; 127 128 n1->next->pre = n2; 129 if (n2->next != NULL) 130 n2->next->pre = n1; 131 132 tmp = n1->next; 133 n1->next = n2->next; 134 n2->next = tmp; 135 136 return 0; 137} 138 139void sortlist(void) { 140 // 選択ソート 141 node *n1; 142 node *minimum = root.next; 143 for (n1=root.next->next; n1->next; n1=n1->next) { 144 node *n2; 145 int d; 146 for (n2=n1->next; n2; n2=n2->next){ 147 if (theta(minimum,n1)>theta(minimum,n2)){ 148 swapNode(n1,n2); 149 // n1が元n2の連結の位置に行き、n2が元n1の連結の位置に行ったため戻す 150 n1 = n2; 151 } 152 printf("%p, %p, %d\n",n1,n2,n1==n2); 153 getc(stdin); 154 } 155 156 } 157} 158 159void convex_hull(void) { 160 node *prevNode = root.next->next, *node = prevNode->next, 161 *nextNode = node->next; 162 int i = 3; 163 //凸包探索開始 164 while (nextNode != &root) { 165 //時計回りかどうかの判定 166 if (checkclockwise(prevNode, node, nextNode) > 0) { 167 //時計回りだったら次の点を探す 168 prevNode = node; 169 node = nextNode; 170 ; 171 nextNode = nextNode->next; 172 i++; 173 } else { 174 //反時計回りだったら1個前の点にする 175 prevNode = prevNode->pre; 176 node = node->pre; 177 delete_node(i); 178 i--; 179 } 180 } 181} 182 183int main(void) { 184 point a; 185 int idx = 0; 186 root.next = root.pre = NULL; 187 188 FILE *input = fopen("points.csv", "r"); 189 190 if (input == NULL) { 191 printf("開くのに失敗しました。"); 192 return 1; 193 } 194 195 //座標をリストに追加していく 196 while (fscanf(input, "%lf,%lf", &a.x, &a.y) != EOF) { 197 addNode(a); 198 } 199 200 fclose(input); 201 printf("input ok\n"); 202 203 // Yが一番小さいノードを基準P0にするため取得(複数あった場合はXの小さいものを選ぶ) 204 node *minnode = find_bottom(); 205 printf("find bottom ok. pos=(%lf,%lf)\n", minnode->data.x, minnode->data.y); 206 //基準を先頭にする 207 swapNode(root.next, minnode); 208 printf("swapnode ok\n"); 209 //基準との角度で並び替え 210 for(node *n=root.next;n;n=n->next) 211 printf("%lf,%lf\n",n->data.x,n->data.y); 212 213 //ここまでオッケー 214 sortlist(); 215 printf("sortlist ok\n"); 216 for(node *n=root.next->next;n;n=n->next) 217 printf("%lf\n",theta(root.next,n)); 218 //同じ角度のものを消す 219 delete_theta(); 220 printf("delete theta ok\n"); 221 222 convex_hull(); 223 printf("convex hull ok\n"); 224 225 FILE *output = fopen("output.csv", "w"); 226 if (output == NULL) { 227 printf("開くのに失敗しました。"); 228 return 1; 229 } 230 231 node *n = root.next; 232 233 while (n != &root) { 234 fprintf(output, "%lf, %lf\n", n->data.x, n->data.y); 235 *n = *n->next; 236 } 237 238 fclose(output); 239 240 return 0; 241}

試したこと

printf("OK")などでデバッグを試みた

補足情報(FW/ツールのバージョンなど)

開発環境
Visual Studio Code
Ubunts 20.04

参考文献
[1]https://www.youtube.com/watch?v=B2AJoQSZf4M
「 Convex Hull Algorithm - Graham Scan and Jarvis March tutorial」

input用のcsvファイルです

csv

1-0.5,1.5 20.5,1.4 31.0,1.0 40.0,0.0 52.0,2.0 60.0,1.0 71.0,0.0 80.8,0.3

ここにより詳細な情報を記載してください。

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

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

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

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

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

jimbe

2022/02/08 17:33

> printf("OK")などでデバッグを試みた その結果、どの様に表示されたのでしょう。
guest

回答3

0

ベストアンサー

98行目の

c

1 if (theta(min, n) == theta(min, n->next)) {

にあるn->nextがリストの最後でNULLになってますね。
そしてtheta関数内の point2->data.xがNULL参照を起こして落ちてます。

投稿2022/02/11 13:43

退会済みユーザー

退会済みユーザー

総合スコア0

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

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

退会済みユーザー

退会済みユーザー

2022/02/11 13:48

あと補足ですが、ubuntuでgdbが使えるのであればvscodeからデバッグするのがおすすめです。
guest

0

双方向リストの最後は next==NULL なのでしょうか、それとも next==&root なのでしょうか。

投稿2022/02/08 17:44

編集2022/02/08 17:46
jimbe

総合スコア12646

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

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

0

例外で停止するようなプログラムをプリントデバッグする場合には適当なタイミングでフラッシュしないと、コードは実行されてもメッセージが画面に出力されないまま終了してしまう場合があります。
手元で試したところでは、ちゃんとフラッシュすれば「sortlist ok」も出力されます。(環境によって結果が変わる類のバグの可能性もありますが)
それを踏まえてもう一度デバッグしてみるといいと思います。

投稿2022/02/08 14:17

yudedako67

総合スコア2047

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

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問