次のプログラムは、ある値がリストの中にあるかどうかを調べるプログラムです。
コード:
#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つの値をどうやって指定するんですか?