ポインタ リスト交換

フォーラム(掲示板)ルール
フォーラム(掲示板)ルールはこちら  ※コードを貼り付ける場合は [code][/code] で囲って下さい。詳しくはこちら
sim
記事: 48
登録日時: 10年前

ポインタ リスト交換

#1

投稿記事 by sim » 9年前

こんばんわ。いつもお世話になっています。
リストの中から、二つを入力して、要素を入れ替えるプログラムがわかりません。
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");
}

超初級者
記事: 56
登録日時: 10年前

Re: ポインタ リスト交換

#2

投稿記事 by 超初級者 » 9年前

二つを入力、というのは、
二つの値
のことですか?それとも
二つの番号
のことですか?

sim
記事: 48
登録日時: 10年前

Re: ポインタ リスト交換

#3

投稿記事 by sim » 9年前

12345678910
たとえば、d1を2.d2を9だったら、
19345678210
となるようにしたいです。

box
記事: 2002
登録日時: 14年前

Re: ポインタ リスト交換

#4

投稿記事 by box » 9年前

sim さんが書きました:12345678910
これは何を表わしているんですか?

1 → 2 → 3 → 4 → 5 → 6 → 7 → 8 → 9 → 10
というリスト構造ですか?
だとすると、「何番目」と「そこの値」が同じになっているので、
「2つの値」というのがどっちのことなのかわかりません。
バグのないプログラムはない。
プログラムは思ったとおりには動かない。書いたとおりに動く。

かずま

Re: ポインタ リスト交換

#5

投稿記事 by かずま » 9年前

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");
}

sim
記事: 48
登録日時: 10年前

Re: ポインタ リスト交換

#6

投稿記事 by sim » 9年前

12345678910
リストの中から、2つ選択して入れ替えるということです。

sim
記事: 48
登録日時: 10年前

Re: ポインタ リスト交換

#7

投稿記事 by sim » 9年前

d1->next=d2;
d2->start=d1;
これって使えますか?

アバター
みけCAT
記事: 6734
登録日時: 14年前
住所: 千葉県
連絡を取る:

Re: ポインタ リスト交換

#8

投稿記事 by みけCAT » 9年前

sim さんが書きました:d1->next=d2;
d2->start=d1;
これって使えますか?
使える状況もあるかもしれませんが、
d1, d2がint型であるこのプログラムでは使えません。
ちなみに、このプログラムのstruct nodeにはstartというメンバは無いですね。
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)

sim
記事: 48
登録日時: 10年前

Re: ポインタ リスト交換

#9

投稿記事 by sim » 9年前

int型であるd1,d2の入れ替えがわかりません。

sim
記事: 48
登録日時: 10年前

Re: ポインタ リスト交換

#10

投稿記事 by sim » 9年前

for(p = start; p != NULL; && d1! = p->data; p = p->next)
for(p = start; p != NULL; && d2! = p->data; p = p->next)
この条件が使えません。

sim
記事: 48
登録日時: 10年前

Re: ポインタ リスト交換

#11

投稿記事 by sim » 9年前

コード:

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;
				}	
			}
		}
	
最後に編集したユーザー sim on 2015年10月22日(木) 18:54 [ 編集 1 回目 ]

sim
記事: 48
登録日時: 10年前

Re: ポインタ リスト交換

#12

投稿記事 by sim » 9年前

とりあえず、/**/の部分を二つ考えました。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: ポインタ リスト交換

#13

投稿記事 by かずま » 9年前

あなたにふさわしい回答をするためには、幾つか疑問な点があって、
複数の回答者が、あなたに質問しているのに、あなたはそれに応えていません。
これではもう誰からも回答をもらえないでしょう。
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 は何か、なども書いてください。

実行時エラーなら、どんな入力をし、どんな出力が表示されるのか、そして
期待する出力は何か、を書いてください。異常終了するのならそう書いてください

アバター
みけCAT
記事: 6734
登録日時: 14年前
住所: 千葉県
連絡を取る:

Re: ポインタ リスト交換

#14

投稿記事 by みけCAT » 9年前

sim さんが書きました:とりあえず、/**/の部分を二つ考えました。1,2どちらもうまくできません。
ご指摘よろしくお願いします「。
共通して言えることとして、startもしくはp1やp2の前のノードのnextを書き換える必要があるかもしれません。
(そもそもやりたいことを正しく理解できているか怪しいですが…)
図を描いて考えるといいかもしれません。

【追記】
1ではp1やp2の前のノードの操作が必要になりそうです。
2ではp1やp2を入れ替えたいノード(?)の前のノードにすることでこの問題の解決を試みているようですが、startが入れ替えたいノードを指している場合に誤動作しそうです。

1でやっていることの例
pointa_risutokoukan_20151022_1.png
1でやっていることの例
pointa_risutokoukan_20151022_1.png (4.59 KiB) 閲覧数: 12381 回
2でやっていることの例
pointa_risutokoukan_20151022_2.png
2でやっていることの例
pointa_risutokoukan_20151022_2.png (5.48 KiB) 閲覧数: 12381 回
やりたいこと?
pointa_risutokoukan_20151022_3.png
やりたいこと?
pointa_risutokoukan_20151022_3.png (4.8 KiB) 閲覧数: 12381 回
sim さんが書きました:1は、19~21行目のnextをstartに変えるとできる。
本当ですか?struct nodeにstartというメンバは無いので、もしもp1やp2がstruct node*型ならコンパイルエラーになるはずだと思うのですが…
ということは、p1やp2はstruct node*型ではないのでしょうか?
sim さんが書きました:next(アドレス)を入れ替えがしたいです。アルゴリズム的に。/**/のみを使って。
意味がよくわかりません。もう少し詳しくお願いします。
最後に編集したユーザー みけCAT on 2015年10月22日(木) 22:08 [ 編集 1 回目 ]
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)

アバター
みけCAT
記事: 6734
登録日時: 14年前
住所: 千葉県
連絡を取る:

Re: ポインタ リスト交換

#15

投稿記事 by みけCAT » 9年前

図を追加。

2でやっていることの例 その2
pointa_risutokoukan_20151022_4.png
2でやっていることの例 その2
pointa_risutokoukan_20151022_4.png (3.85 KiB) 閲覧数: 12376 回
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)

アバター
みけCAT
記事: 6734
登録日時: 14年前
住所: 千葉県
連絡を取る:

Re: ポインタ リスト交換

#16

投稿記事 by みけCAT » 9年前

よく見たら、1も2も探索処理のループの中に入れ替え処理が入っていることがおかしくなる原因の一つである気がしました。
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)

かずま

Re: ポインタ リスト交換

#17

投稿記事 by かずま » 9年前

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: ポインタ リスト交換

#18

投稿記事 by かずま » 9年前

かずま さんが書きました:

コード:

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: ポインタ リスト交換

#19

投稿記事 by かずま » 9年前

別解

コード:

        /* ここ */
        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 が見つかったら、あとは見ません。

sim
記事: 48
登録日時: 10年前

Re: ポインタ リスト交換

#20

投稿記事 by sim » 9年前

head.nextって何してる処理ですか?

sim
記事: 48
登録日時: 10年前

Re: ポインタ リスト交換

#21

投稿記事 by sim » 9年前

あと、次の値を入力するとコアダンプがでます。Linuxです。

sim
記事: 48
登録日時: 10年前

Re: ポインタ リスト交換

#22

投稿記事 by sim » 9年前

コアダンプは直しました。自分のミスです。
head.nextの意味教えて下さい。

アバター
みけCAT
記事: 6734
登録日時: 14年前
住所: 千葉県
連絡を取る:

Re: ポインタ リスト交換

#23

投稿記事 by みけCAT » 9年前

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)
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)

sim
記事: 48
登録日時: 10年前

Re: ポインタ リスト交換

#24

投稿記事 by sim » 9年前

どのような働きをするんでしょうか?
すみません。

アバター
みけCAT
記事: 6734
登録日時: 14年前
住所: 千葉県
連絡を取る:

Re: ポインタ リスト交換

#25

投稿記事 by みけCAT » 9年前

先頭を他のノードと同じstruct node型に格納することで、特別扱いせずにすむようにしているようですね。
オフトピック
このプログラムだと、同じ値が2個以上のノードにあって、それがd1またはd2と一致していると、
d1とd1、またはd2とd2のノード同士を交換してd1とd2の交換にならないケースが出てきそうだなあ。
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)

sim
記事: 48
登録日時: 10年前

Re: ポインタ リスト交換

#26

投稿記事 by sim » 9年前

先頭を構造体に格納して、入れ替えするんですね?
最後のstart=head.nextは同じ意味ではないですか?
head.next=startでは出来ませんでした。

かずま

Re: ポインタ リスト交換

#27

投稿記事 by かずま » 9年前

次のプログラムは、ある値がリストの中にあるかどうかを調べるプログラムです。

コード:

#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つの値をどうやって指定するんですか?

アバター
みけCAT
記事: 6734
登録日時: 14年前
住所: 千葉県
連絡を取る:

Re: ポインタ リスト交換

#28

投稿記事 by みけCAT » 9年前

sim さんが書きました:最後のstart=head.nextは同じ意味ではないですか?
「同じ意味」かどうかはよくわかりません(そもそも何と?)が、
head.next = start;とstart = head.next;は同じ目的の処理のために書かれており、
head.next = start;はダミーのノードに先頭の位置を入れる処理、
start = head.next;はダミーのノードに記録された先頭の位置の更新をメインのプログラムに反映させる処理だと思います。
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)

かずま

Re: ポインタ リスト交換

#29

投稿記事 by かずま » 9年前

間違い発見。
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);
    }
}

閉鎖

“C言語何でも質問掲示板” へ戻る