ページ 1 / 1
ポインタ リスト交換
Posted: 2015年10月20日(火) 20:52
by sim
こんばんわ。いつもお世話になっています。
リストの中から、二つを入力して、要素を入れ替えるプログラムがわかりません。
startからNULLまで(d1、d2)どうやって見るのか。
なお、/**/の部分に追加するようにしたいです。よろしくお願いします。
コード:
#include<stdio.h>
#include<stdlib.h>
/*構造体の宣言*/
struct node
{
int data;
struct node *next;
};
void print_list(struct node *start);
int main(void)
{
/*変数宣言*/
struct node *start,*p;
int d1,d2,i;
/*リストを初期化する*/
start = NULL;
/*リストを生成する*/
for(i=1; i<=10; i++)
{
/*要素を作成する*/
if(start == NULL)
{
p = malloc(sizeof(struct node));
start = p;
}
else
{
p->next = malloc(sizeof(struct node));
p = p->next;
}
p->data = i;
p->next = NULL;
}
/*交換要素を入力する*/
printf("LIST : ");
print_list(start);
printf("Input 2 Numder : ");
scanf("%d %d , &d1, &d2");
while(d1 > 0 && d2 > 0)
{
/*ここ
まで */
/*次の交換要素を入力する*/
printf("LIST : ");
print_list(start);
printf("Input 2 Numder : ");
scanf("%d %d , &d1,&d2");
}
/*結果を出力する*/
printf("Result : ");
print_list(start);
return 0;
}
void print_list(struct node *start)
{
struct node *p;
for(p=start; p!=NULL; p=p->next)
{
printf("%d",p->data);
}
printf("\n");
}
Re: ポインタ リスト交換
Posted: 2015年10月20日(火) 21:03
by 超初級者
二つを入力、というのは、
二つの値
のことですか?それとも
二つの番号
のことですか?
Re: ポインタ リスト交換
Posted: 2015年10月20日(火) 21:06
by sim
12345678910
たとえば、d1を2.d2を9だったら、
19345678210
となるようにしたいです。
Re: ポインタ リスト交換
Posted: 2015年10月20日(火) 23:34
by box
sim さんが書きました:12345678910
これは何を表わしているんですか?
1 → 2 → 3 → 4 → 5 → 6 → 7 → 8 → 9 → 10
というリスト構造ですか?
だとすると、「何番目」と「そこの値」が同じになっているので、
「2つの値」というのがどっちのことなのかわかりません。
Re: ポインタ リスト交換
Posted: 2015年10月21日(水) 04:24
by かずま
dataだけを入れ替えるインチキプログラム
コード:
#include <stdio.h>
#include <stdlib.h>
struct node {
int data;
struct node *next;
};
int get_numbers(const struct node * start, int *d1, int *d2);
void print_list(const struct node *start);
int main(void)
{
struct node *start, *p = NULL;
int d1, d2, i;
start = NULL;
for (i = 1; i <= 10; i++) {
struct node *tail = p;
p = malloc(sizeof(struct node));
p->data = i;
p->next = NULL;
if (start == NULL)
start = p;
else
tail->next = p;
}
while (get_numbers(start, &d1, &d2)) {
struct node *p1 = NULL, *p2 = NULL;
for (p = start; p != NULL; p = p->next)
if (p->data == d1)
p1 = p;
else if (p->data == d2)
p2 = p;
if (p1 != NULL && p2 != NULL)
i = p1->data, p1->data = p2->data, p2->data = i;
print_list(start);
}
return 0;
}
int get_numbers(const struct node *start, int *d1, int *d2)
{
printf("LIST : ");
print_list(start);
printf("Input 2 Numders : ");
return scanf("%d%d", d1, d2) == 2 && *d1 > 0 && *d2 > 0;
}
void print_list(const struct node *p)
{
for( ; p != NULL; p = p->next)
printf(" %d", p->data);
printf("\n");
}
リンクをつなぎ変えて「要素」を入れ替えるプログラム
コード:
#include <stdio.h>
#include <stdlib.h>
struct node {
int data;
struct node *next;
};
int get_numbers(const struct node * start, int *d1, int *d2);
void print_list(const struct node *start);
int main(void)
{
struct node *start, *p = NULL;
int d1, d2, i;
start = NULL;
for (i = 1; i <= 10; i++) {
struct node *tail = p;
p = malloc(sizeof(struct node));
p->data = i;
p->next = NULL;
if (start == NULL)
start = p;
else
tail->next = p;
}
while (get_numbers(start, &d1, &d2)) {
struct node head, *p1 = NULL, *p2 = NULL;
head.next = start;
for (p = &head; p->next != NULL; p = p->next)
if (p->next->data == d1)
p1 = p;
else if (p->next->data == d2)
p2 = p;
if (p1 != NULL && p2 != NULL) {
if (p1->next == p2) {
p1->next = p2->next;
p2->next = p2->next->next;
p1->next->next = p2;
}
else if (p2->next == p1) {
p2->next = p1->next;
p1->next = p1->next->next;
p2->next->next = p1;
}
else {
struct node *q = p1->next->next;
p1->next->next = p2->next->next;
p2->next->next = q;
q = p1->next;
p1->next = p2->next;
p2->next= q;
}
}
start = head.next;
print_list(start);
}
return 0;
}
int get_numbers(const struct node *start, int *d1, int *d2)
{
printf("LIST : ");
print_list(start);
printf("Input 2 Numders : ");
return scanf("%d%d", d1, d2) == 2 && *d1 > 0 && *d2 > 0;
}
void print_list(const struct node *p)
{
for( ; p != NULL; p = p->next)
printf(" %d", p->data);
printf("\n");
}
Re: ポインタ リスト交換
Posted: 2015年10月21日(水) 14:41
by sim
12345678910
リストの中から、2つ選択して入れ替えるということです。
Re: ポインタ リスト交換
Posted: 2015年10月21日(水) 18:06
by sim
d1->next=d2;
d2->start=d1;
これって使えますか?
Re: ポインタ リスト交換
Posted: 2015年10月21日(水) 18:19
by みけCAT
sim さんが書きました:d1->next=d2;
d2->start=d1;
これって使えますか?
使える状況もあるかもしれませんが、
d1, d2がint型であるこのプログラムでは使えません。
ちなみに、このプログラムのstruct nodeにはstartというメンバは無いですね。
Re: ポインタ リスト交換
Posted: 2015年10月21日(水) 18:38
by sim
int型であるd1,d2の入れ替えがわかりません。
Re: ポインタ リスト交換
Posted: 2015年10月21日(水) 20:10
by sim
for(p = start; p != NULL; && d1! = p->data; p = p->next)
for(p = start; p != NULL; && d2! = p->data; p = p->next)
この条件が使えません。
Re: ポインタ リスト交換
Posted: 2015年10月22日(木) 18:47
by sim
コード:
while(d1 > 0 && d2 > 0)
{
p1 = NULL;
p2 = NULL;
/*選択する要素を探索する*/
for(p=start;p!=NULL;p=p->next)
{
if(p->data == d1)
{
p1 = p;
}
else if(p->data == d2)
{
p2 = p;
}
if(p1 != NULL && p2 != NULL)
{
q = p1->next;
p1->next = p2->next;
p2->next = q;
}
}
コード:
while(d1 > 0 && d2 > 0)
{
p1 = NULL;
p2 = NULL;
/*選択する要素を探索する*/
for(p=start;p!=NULL;p=p->next)
{
if(p->next->data == d1)
{
p1 = p;
}
else if(p->next->data == d2)
{
p2 = p;
}
if(p1 != NULL && p2 != NULL)
{
if(p1->next == p2)
{
p1->next = p2->next;
p2->next = p2->next->next;
p1->next->next = p2;
}
else if(p2->next == p1)
{
p2->next = p1->next;
p1->next = p1->next->next;
p2->next->next = p1;
}
else
{
q = p1->next->next;
p1->next->next = p2->next->next;
p2->next->next = q;
q = p1->next;
p1->next = p2->next;
p2->next = q;
}
}
}
Re: ポインタ リスト交換
Posted: 2015年10月22日(木) 18:53
by sim
とりあえず、/**/の部分を二つ考えました。1,2どちらもうまくできません。
ご指摘よろしくお願いします「。
1、
コード:
while(d1 > 0 && d2 > 0)
{
p1 = NULL;
p2 = NULL;
/*選択する要素を探索する*/
for(p=start;p!=NULL;p=p->next)
{
if(p->data == d1)
{
p1 = p;
}
else if(p->data == d2)
{
p2 = p;
}
if(p1 != NULL && p2 != NULL)
{
q = p1->next;
p1->next = p2->next;
p2->next = q;
}
}
2、
コード:
while(d1 > 0 && d2 > 0)
{
p1 = NULL;
p2 = NULL;
/*選択する要素を探索する*/
for(p=start;p!=NULL;p=p->next)
{
if(p->next->data == d1)
{
p1 = p;
}
else if(p->next->data == d2)
{
p2 = p;
}
if(p1 != NULL && p2 != NULL)
{
if(p1->next == p2)
{
p1->next = p2->next;
p2->next = p2->next->next;
p1->next->next = p2;
}
else if(p2->next == p1)
{
p2->next = p1->next;
p1->next = p1->next->next;
p2->next->next = p1;
}
else
{
q = p1->next->next;
p1->next->next = p2->next->next;
p2->next->next = q;
q = p1->next;
p1->next = p2->next;
p2->next = q;
}
}
}
1は、19~21行目のnextをstartに変えるとできる。しかし、next(アドレス)を入れ替えるようにしたい。
2は、入力が無限に続いてしまう。
どちらにせよ、うまくできません。next(アドレス)を入れ替えがしたいです。アルゴリズム的に。/**/のみを使って。
よろしくお願いします。
Re: ポインタ リスト交換
Posted: 2015年10月22日(木) 21:36
by かずま
あなたにふさわしい回答をするためには、幾つか疑問な点があって、
複数の回答者が、あなたに質問しているのに、あなたはそれに応えていません。
これではもう誰からも回答をもらえないでしょう。
12345678910
たとえば、d1を2.d2を9だったら、
19345678210
となるようにしたいです。
では、その次に、d1 を 5、d2 を 9 としたら、どうなるんでしょうか?
「二つの値」(「そこの値」)だったら、15349678210
「二つの番号」(「何番目」)だったら、19342678510
それから、リストをなぜ、間に空白を置かずに並べるんですか?
12345678910 は 11桁のひとつの数に見えます。
最初に、6 7 8 9 10 11 12 13 14 15 の 10個の数のリストを作ったとしたら、
6789101112131415 と表示するんですか?
これで、2つの値をどうやって指定するんですか?
それから、/*ここ まで*/ 以外のところを変更しないとすれば、
scanf("%d %d , &d1, &d2"); が実行時エラーになりますよ。
コンパイラが警告を発する場合もあります。
また、あなたが書いたプログラムは p1, p2, q の宣言がありません。
「うまくできません」ではなく、
コンパイルエラーなら、エラーメッセージをそのままコピペしてください。
コンパイラは何か、OS は何か、なども書いてください。
実行時エラーなら、どんな入力をし、どんな出力が表示されるのか、そして
期待する出力は何か、を書いてください。異常終了するのならそう書いてください
Re: ポインタ リスト交換
Posted: 2015年10月22日(木) 22:00
by みけCAT
sim さんが書きました:とりあえず、/**/の部分を二つ考えました。1,2どちらもうまくできません。
ご指摘よろしくお願いします「。
共通して言えることとして、startもしくはp1やp2の前のノードのnextを書き換える必要があるかもしれません。
(そもそもやりたいことを正しく理解できているか怪しいですが…)
図を描いて考えるといいかもしれません。
【追記】
1ではp1やp2の前のノードの操作が必要になりそうです。
2ではp1やp2を入れ替えたいノード(?)の前のノードにすることでこの問題の解決を試みているようですが、startが入れ替えたいノードを指している場合に誤動作しそうです。
1でやっていることの例

- 1でやっていることの例
- pointa_risutokoukan_20151022_1.png (4.59 KiB) 閲覧数: 12380 回
2でやっていることの例

- 2でやっていることの例
- pointa_risutokoukan_20151022_2.png (5.48 KiB) 閲覧数: 12380 回
やりたいこと?

- やりたいこと?
- pointa_risutokoukan_20151022_3.png (4.8 KiB) 閲覧数: 12380 回
sim さんが書きました:1は、19~21行目のnextをstartに変えるとできる。
本当ですか?struct nodeにstartというメンバは無いので、もしもp1やp2がstruct node*型ならコンパイルエラーになるはずだと思うのですが…
ということは、p1やp2はstruct node*型ではないのでしょうか?
sim さんが書きました:next(アドレス)を入れ替えがしたいです。アルゴリズム的に。/**/のみを使って。
意味がよくわかりません。もう少し詳しくお願いします。
Re: ポインタ リスト交換
Posted: 2015年10月22日(木) 22:04
by みけCAT
図を追加。
2でやっていることの例 その2

- 2でやっていることの例 その2
- pointa_risutokoukan_20151022_4.png (3.85 KiB) 閲覧数: 12375 回
Re: ポインタ リスト交換
Posted: 2015年10月22日(木) 22:06
by みけCAT
よく見たら、1も2も探索処理のループの中に入れ替え処理が入っていることがおかしくなる原因の一つである気がしました。
Re: ポインタ リスト交換
Posted: 2015年10月23日(金) 01:37
by かずま
sim さんが書きました:とりあえず、/**/の部分を二つ考えました。1,2どちらもうまくできません。
ご指摘よろしくお願いします「。
紙に鉛筆で図を描いてみることができませんか?
1 について、見てみます。
コード:
最初の状態
+-----+ +-----+ +-----+
start| * | p1| * | p2| * |
+--|--+ +--|--+ +--|--+
V V V struct node
+-----+ +-----+ +-----+ +-----+ +-----+ +-----+ +-----+
| | | | | d1 | | | | d2 | | | | |.data
+-----+ +-----+ +-----+ +-----+ +-----+ +-----+ +-----+
| *------>| *------>| *------>| *------>| *------>| *------>| NULL|.next
+-----+ +-----+ +-----+ +-----+ +-----+ +-----+ +-----+
q = p1->next; を実行すると、
+-----+ +-----+ +-----+ +-----+
start| * | p1| * | q| * | p2| * |
+--|--+ +--|--+ +--|--+ +--|--+
V V V V struct node
+-----+ +-----+ +-----+ +-----+ +-----+ +-----+ +-----+
| | | | | d1 | | | | d2 | | | | |.data
+-----+ +-----+ +-----+ +-----+ +-----+ +-----+ +-----+
| *------>| *------>| *------>| *------>| *------>| *------>| NULL|.next
+-----+ +-----+ +-----+ +-----+ +-----+ +-----+ +-----+
p1->next = p2->next; を実行すると、
+-----+ +-----+ +-----+ +-----+
start| * | p1| * | q| * | p2| * |
+--|--+ +--|--+ +--|--+ +--|--+
V V V V struct node
+-----+ +-----+ +-----+ +-----+ +-----+ +-----+ +-----+
| | | | | d1 | | | | d2 | | | | |.data
+-----+ +-----+ +-----+ +-----+ +-----+ +-----+ +-----+
| *------>| *------>| * | | *------>| *------>| *------>| NULL|.next
+-----+ +-----+ +--|--+ +-----+ +-----+ +-----+ +-----+
| A
+--------------------------------+
p2->next = q; を実行すると、
+-----+ +-----+ +-----+ +-----+
start| * | p1| * | q| * | p2| * |
+--|--+ +--|--+ +--|--+ +--|--+
V V V V struct node
+-----+ +-----+ +-----+ +-----+ +-----+ +-----+ +-----+
| | | | | d1 | | | | d2 | | | | |.data
+-----+ +-----+ +-----+ +-----+ +-----+ +-----+ +-----+
| *------>| *------>| * | | *------>| *------>| *------>| NULL|.next
+-----+ +-----+ +--|--+ +-----+ +--|--+ +-----+ +-----+
| A | A
| +----------+ |
+--------------------------------+
これが、あなたの 1 の実行結果です。
start からたどって、ちゃんとしたリストになっていませんよね。
実際には次のようになるべきです。
+-----+ +-----+ +-----+ +-----+ +-----+
start| * | r| * | p1| * | q| * | p2| * |
+--|--+ +--|--+ +--|--+ +--|--+ +--|--+
V V V V V struct node
+-----+ +-----+ +-----+ +-----+ +-----+ +-----+ +-----+
| | | | | d1 | | | | d2 | | | | |.data
+-----+ +-----+ +-----+ +-----+ +-----+ +-----+ +-----+
| *------>| * | | * | | * | | * | | *------>| NULL|.next
+-----+ +--|--+ +-|---+ +-|---+ +-|---+ +-----+ +-----+
| | A | A | A A
| | +-------+ +-------+ | |
| +------------------------+--------+
| }
+----------------------------------+
すなわち、変更するべきものは、p1->next, p2->next, q->next, r->next
わかりますか?
]
Re: ポインタ リスト交換
Posted: 2015年10月24日(土) 13:58
by かずま
かずま さんが書きました:
コード:
p2->next = q; を実行すると、
+-----+ +-----+ +-----+ +-----+
start| * | p1| * | q| * | p2| * |
+--|--+ +--|--+ +--|--+ +--|--+
V V V V struct node
+-----+ +-----+ +-----+ +-----+ +-----+ +-----+ +-----+
| | | | | d1 | | | | d2 | | | | |.data
+-----+ +-----+ +-----+ +-----+ +-----+ +-----+ +-----+
| *------>| *------>| * | | *------>| *------>| *------>| NULL|.next
+-----+ +-----+ +--|--+ +-----+ +--|--+ +-----+ +-----+
| A | A
| +----------+ |
+--------------------------------+
]
d2 のノードで右のノードへの矢印は間違いです。削除してください。下だけです。
sim さんが書きました:1は、19~21行目のnextをstartに変えるとできる。
1 は、19~21行目の next を data に変えるとできる、ですよね。
すなわち、私の提示したインチキプログラムのように。
d1 のノードと d2 のノードを交換したかったら、d1、d2 の next だけでなく、
d1 と d2 のノードを指している直前のノードの next も変更しないといけない
ことは分かりますよね。
コード:
#include<stdio.h>
#include<stdlib.h>
/*構造体の宣言*/
struct node
{
int data;
struct node *next;
};
void print_list(struct node *start);
int main(void)
{
/*変数宣言*/
struct node *start,*p;
int d1,d2,i;
/*リストを初期化する*/
start = NULL;
/*リストを生成する*/
for(i=1; i<=10; i++)
{
/*要素を作成する*/
if(start == NULL)
{
p = malloc(sizeof(struct node));
start = p;
}
else
{
p->next = malloc(sizeof(struct node));
p = p->next;
}
p->data = i;
p->next = NULL;
}
/*交換要素を入力する*/
printf("LIST : ");
print_list(start);
printf("Input 2 Numder : ");
if (scanf("%d %d", &d1, &d2) != 2) return 1;
while(d1 > 0 && d2 > 0)
{
/* ここ */
struct node head, *p1 = NULL, *p2 = NULL;
head.next = start;
for (p = &head; p->next != NULL; p = p->next)
{
if (p->next->data == d1)
{
p1 = p;
}
else if (p->next->data == d2)
{
p2 = p;
}
}
if (p1 != NULL && p2 != NULL) {
if (p1->next == p2)
{
p1->next = p2->next;
p2->next = p2->next->next;
p1->next->next = p2;
}
else if (p2->next == p1)
{
p2->next = p1->next;
p1->next = p1->next->next;
p2->next->next = p1;
}
else
{
p = p1->next->next;
p1->next->next = p2->next->next;
p2->next->next = p;
p = p1->next;
p1->next = p2->next;
p2->next = p;
}
start = head.next;
}
/* まで */
/*次の交換要素を入力する*/
printf("LIST : ");
print_list(start);
printf("Input 2 Numder : ");
if (scanf("%d %d", &d1,&d2) != 2) return 1;
}
/*結果を出力する*/
printf("Result : ");
print_list(start);
return 0;
}
void print_list(struct node *start)
{
struct node *p;
for(p=start; p!=NULL; p=p->next)
{
printf("%d",p->data);
}
printf("\n");
}
/*ここ まで*/ 以外は scanf() の行しか変更していません。
これで満足ですか?
理解できなければ、どこが分からないのかを質問してください。
Re: ポインタ リスト交換
Posted: 2015年10月26日(月) 21:25
by かずま
別解
コード:
/* ここ */
struct node head, *p1 = NULL, *p2 = NULL;
head.next = start;
for (p = &head; p->next != NULL; p = p->next) {
if (p->next->data == d1 || p->next->data == d2) {
if (p1 == NULL) p1 = p;
else { p2 = p; break; }
}
}
if (p2 != NULL) {
if (p1->next == p2) {
p1->next = p2->next;
p2->next = p2->next->next;
p1->next->next = p2;
}
else {
#define SWAP(a, b) (p = a, a = b, b = p)
SWAP(p1->next->next, p2->next->next);
SWAP(p1->next, p2->next);
}
start = head.next;
}
/* まで */
必ず p1 が p2 より先に来ます。p2 が見つかったら、あとは見ません。
Re: ポインタ リスト交換
Posted: 2015年10月28日(水) 16:49
by sim
head.nextって何してる処理ですか?
Re: ポインタ リスト交換
Posted: 2015年10月28日(水) 17:22
by sim
あと、次の値を入力するとコアダンプがでます。Linuxです。
Re: ポインタ リスト交換
Posted: 2015年10月28日(水) 22:13
by sim
コアダンプは直しました。自分のミスです。
head.nextの意味教えて下さい。
Re: ポインタ リスト交換
Posted: 2015年10月28日(水) 22:46
by みけCAT
sim さんが書きました:head.nextの意味教えて下さい。
構造体変数headのnextというメンバという意味です。
N1256 6.5.2.3 Structure and union members さんが書きました:
Constraints
1 The first operand of the . operator shall have a qualified or unqualified structure or union
type, and the second operand shall name a member of that type.
(中略)
Semantics
3 A postfix expression followed by the . operator and an identifier designates a member of
a structure or union object. The value is that of the named member, 82) and is an lv alue if
the first expression is an lvalue. If the first expression has qualified type, the result has
the so-qualified version of the type of the designated member.
(
http://www.open-std.org/jtc1/sc22/wg14/ ... /n1256.pdf)
Re: ポインタ リスト交換
Posted: 2015年10月28日(水) 22:56
by sim
どのような働きをするんでしょうか?
すみません。
Re: ポインタ リスト交換
Posted: 2015年10月28日(水) 23:26
by みけCAT
先頭を他のノードと同じstruct node型に格納することで、特別扱いせずにすむようにしているようですね。
オフトピック
このプログラムだと、同じ値が2個以上のノードにあって、それがd1またはd2と一致していると、
d1とd1、またはd2とd2のノード同士を交換してd1とd2の交換にならないケースが出てきそうだなあ。
Re: ポインタ リスト交換
Posted: 2015年10月28日(水) 23:40
by sim
先頭を構造体に格納して、入れ替えするんですね?
最後のstart=head.nextは同じ意味ではないですか?
head.next=startでは出来ませんでした。
Re: ポインタ リスト交換
Posted: 2015年10月29日(木) 04:31
by かずま
次のプログラムは、ある値がリストの中にあるかどうかを調べるプログラムです。
コード:
#include <stdio.h>
struct node {
int data;
struct node *next;
};
struct node list[] = {
{ 11, list + 1 },
{ 22, list + 2 },
{ 33, list + 3 },
{ 44, list + 4 },
{ 55, NULL },
};
void print_list(const struct node *p)
{
for (; p != NULL; p = p->next)
printf(" %d", p->data);
putchar('\n');
}
int main(void)
{
int d;
struct node *start, *p;
start = list;
print_list(start);
while (printf("input a number; "), scanf("%d", &d) == 1) {
for (p = start; p != NULL && p->data != d; p = p->next) ;
if (p != NULL)
printf("%d found\n", d);
else
printf("%d not found\n", d);
}
return 0;
}
このように、リストを先頭から順にたどって、リストの要素(ノード)を見ることは
簡単です。
では、見つけたノードを削除するというプログラムは書けますか?
コード:
+-----+ +-----+
start| * | p| * |
+--|--+ +--|--+
struct node V V
+-----+ +-----+ +-----+ +-----+ +-----+
.data| 11 | | 22 | | 33 | | 44 | | 55 |
+-----+ +-----+ +-----+ +-----+ +-----+
.next| *------->| *------->| *------->| *------->| NULL|
+-----+ +-----+ +-----+ +-----+ +-----+
.data が 22 のノードの .next に p->next を代入すれば、
次のようなって 33 のノードが削除できますよね。
コード:
+-----+ +-----+
start| * | p| * |
+--|--+ +--|--+
struct node V V
+-----+ +-----+ +-----+ +-----+ +-----+
.data| 11 | | 22 | | 33 | | 44 | | 55 |
+-----+ +-----+ +-----+ +-----+ +-----+
.next| *------->| * | | *------->| *------->| NULL|
+-----+ +--|--+ +-----+ +-----+ +-----+
| A
+-----------------------+
ということは、見つけたノードの一つ前のノードを指すポインタも必要です。
それを q とします。
q->next = p->next; を実行すると、次のようになり、33 のノードは削除できました。
コード:
+-----+ +-----+ +-----+
start| * | q| * | p| * |
+--|--+ +--|--+ +--|--+
struct node V V V
+-----+ +-----+ +-----+ +-----+ +-----+
.data| 11 | | 22 | | 33 | | 44 | | 55 |
+-----+ +-----+ +-----+ +-----+ +-----+
.next| *------->| * | | *------->| *------->| NULL|
+-----+ +--|--+ +-----+ +-----+ +-----+
| A
+-----------------------+
では、ポインタは q と p の二ついるのか?
いいえ、二つ入りません。q だけあれば、q->next が p の代わりになります。
すなわち、見つけたいノードの一つ前のノードを指すポインタがあればいいのです。
それを p とします。
コード:
for (p = start; p->next != NULL && p->next->data != d; p = p->next) ;
これで、33 のノードを見つけると、p は 22 のノードを指していて、
p->next が 33 のノードを指しています。
コード:
+-----+ +-----+
start| * | p| * |
+--|--+ +--|--+
struct node V V
+-----+ +-----+ +-----+ +-----+ +-----+
.data| 11 | | 22 | | 33 | | 44 | | 55 |
+-----+ +-----+ +-----+ +-----+ +-----+
.next| *------->| *------->| *------->| *------->| NULL|
+-----+ +-----+ +-----+ +-----+ +-----+
p->next = p->next->next; を実行すると、次のようになって 33 のノードが削除できます。
コード:
+-----+ +-----+
start| * | p| * |
+--|--+ +--|--+
struct node V V
+-----+ +-----+ +-----+ +-----+ +-----+
.data| 11 | | 22 | | 33 | | 44 | | 55 |
+-----+ +-----+ +-----+ +-----+ +-----+
.next| *------->| * | | *------->| *------->| NULL|
+-----+ +--|--+ +-----+ +-----+ +-----+
| A
+-----------------------+
ところが、これだと先頭の 11 のノードは探せません。
そこで、先頭のノードの一つ前に仮想的なノードをひとつ用意して、
最初に p がそれを指せば、先頭の 11 のノードも見つかります。
コード:
p start
+-----+ +-----+
| | | * |
+--|--+ +--|--+
head V V
+-----+ +-----+ +-----+ +-----+ +-----+ +-----+
| ?? | | 11 | | 22 | | 33 | | 44 | | 55 |
+-----+ +-----+ +-----+ +-----+ +-----+ +-----+
| *------>| *------->| * | | *------->| *------->| NULL|
+-----+ +-----+ +-----+ +-----+ +-----+ +-----+
コード:
head.next = start;
for (p = &head; p->next != NULL && p->next->data != d; p = p->next) ;
これがそのコードです。
私はあなたの質問に答えました。
あなたも私の質問に答えてください。
リストをなぜ、間に空白を置かずに並べるんですか?
12345678910 は 11桁のひとつの数に見えます。
最初に、6 7 8 9 10 11 12 13 14 15 の 10個の数のリストを作ったとしたら、
6789101112131415 と表示するんですか?
これで、2つの値をどうやって指定するんですか?
Re: ポインタ リスト交換
Posted: 2015年10月29日(木) 09:20
by みけCAT
sim さんが書きました:最後のstart=head.nextは同じ意味ではないですか?
「同じ意味」かどうかはよくわかりません(そもそも何と?)が、
head.next = start;とstart = head.next;は同じ目的の処理のために書かれており、
head.next = start;はダミーのノードに先頭の位置を入れる処理、
start = head.next;はダミーのノードに記録された先頭の位置の更新をメインのプログラムに反映させる処理だと思います。
Re: ポインタ リスト交換
Posted: 2015年11月04日(水) 01:53
by かずま
間違い発見。
22 のノードから 33 のノードへの矢印が抜けていました。
次のように訂正します。
コード:
p start
+-----+ +-----+
| | | * |
+--|--+ +--|--+
head V V
+-----+ +-----+ +-----+ +-----+ +-----+ +-----+
| ?? | | 11 | | 22 | | 33 | | 44 | | 55 |
+-----+ +-----+ +-----+ +-----+ +-----+ +-----+
| *------>| *------->| *------->| *------->| *------->| NULL|
+-----+ +-----+ +-----+ +-----+ +-----+ +-----+
head を使ったノード削除のプログラムをもう一度書いておきます。
コード:
#include <stdio.h>
struct node {
int data;
struct node *next;
};
struct node list[] = {
{ 11, list + 1 },
{ 22, list + 2 },
{ 33, list + 3 },
{ 44, list + 4 },
{ 55, NULL },
};
void print_list(const struct node *p)
{
for (; p != NULL; p = p->next)
printf(" %d", p->data);
putchar('\n');
}
int main(void)
{
int d;
struct node *start, *p;
start = list;
print_list(start);
while (printf("input a number; "), scanf("%d", &d) == 1) {
struct node head;
head.next = start;
for (p = &head; p->next != NULL && p->next->data != d; p = p->next) ;
if (p->next != NULL)
p->next = p->next->next;
else
printf("%d not found\n", d);
start = head.next;
print_list(start);
}
return 0;
}
この仮想的なノード head を使わないと、どういうコードになるのでしょうか。
コード:
while (printf("input a number; "), scanf("%d", &d) == 1) {
if (start == NULL)
printf("%d not found\n", d);
else if (start->data == d)
start = start->next;
else {
for (p = start; p->next != NULL && p->next->data != d; p = p->next) ;
if (p->next != NULL)
p->next = p->next->next;
else
printf("%d not found\n", d);
}
print_list(start);
}
御覧のように場合分けが必要になるんですね。
仮想的なノードを使わずに、場合分けもなくす方法もあります。
コード:
while (printf("input a number; "), scanf("%d", &d) == 1) {
struct node **p;
for (p = &start; *p != NULL && (*p)->data != d; p = &(*p)->next) ;
if (*p != NULL)
*p = (*p)->next;
else
printf("%d not found\n", d);
print_list(start);
}
}