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

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

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

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

Q&A

2回答

1807閲覧

単方向連結リストから双方向連結リスト

ldangol

総合スコア6

C

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

0グッド

0クリップ

投稿2016/12/14 08:08

編集2016/12/14 08:17

C言語についての質問です。
以下のソースコードは単方向連結リストです。
これを双方向連結リストに改編し、リストを逆順に表示する ListRevPrintAll 関数を実装したいのですが、わかりません。
どなたか解説付きで教えてくださらないでしょうか。
自分で勉強しての変更点は、
struct cell *prev;
を追加し、
ListInsert関数を
PCELL ListInsert(PCELL pos, const char *string)
{
PCELL pNewCell;
pNewCell = calloc(1, sizeof(CELL));

if (pNewCell != NULL) { // 新しいセルへの文字列をコピーおよび // ポインタの付け替えを行う strcpy(pNewCell->string, string); pNewCell->next = pos->next; pNewCell->next->prev = pNewCell; pos->next = pNewCell; pNewCell->prev = pos; } return pNewCell;

}
とし、ListDelete関数は
void ListDelete(PCELL pos)
{
PCELL P0;
P0 = pos->prev->next = pos->next;
pos->next->prev = pos->prev;
pos->prev = pos->next = pos;
free(P0);

}
と変更しました。
ほかにどのように改編すればよいでしょうか。

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <assert.h>
#include <crtdbg.h>
typedef struct cell {
char string[8];
struct cell *next;
} CELL, *PCELL;

PCELL ListCreate()
{
return calloc(1, sizeof(CELL));
}

PCELL ListGetPrevPos(PCELL header, const char *str)
{
while (header->next) {
if (strcmp(header->next->string, str) == 0) {
return header;
}
header = header->next;
}
return NULL;
}

PCELL ListNext(PCELL pos)
{
return pos->next;
}

void ListPrintAll(PCELL header)
{
puts("- addr -- next -:string");
printf("[%08x][%08x]:HEADER\n", header, header->next);
header = header->next;
while (header) {
printf("[%08x][%08x]:<%s>\n", header, header->next, header->string);
header = header->next;
}
puts("------");
}

PCELL ListInsert(PCELL pos, const char *string)
{
PCELL pNewCell;
pNewCell = calloc(1, sizeof(CELL));

if (pNewCell != NULL) { strcpy(pNewCell->string, string); pNewCell->next = pos->next; pos->next = pNewCell; } return pNewCell;

}

void ListDelete(PCELL pos)
{
PCELL P0;
P0 = pos->next;
pos->next = pos->next->next;
free(P0);

}

void ListDestroy(PCELL header)
{
PCELL P, PC;
PC = header;
while (PC != NULL) {
P = PC->next;
free(PC);
PC = P;
}

}

#define BUFSIZE 20

int main()
{
static char buf[BUFSIZE];
PCELL header;

header = ListCreate(); for (;;) { printf(">>"); gets(buf); switch (*buf) { case 'A': case 'a': printf("先頭に挿入する文字列を入力:"); gets(buf); ListInsert(header, buf); break; case 'I': case 'i': { PCELL pos; printf("挿入位置の文字列を入力:"); gets(buf); pos = ListGetPrevPos(header, buf); if (pos == NULL) { printf("\"%s\"は見つかりません\n", buf); } else { printf("挿入する文字列を入力:"); gets(buf); ListInsert(ListNext(pos), buf); } } break; case 'D': case 'd': { PCELL pos; printf("削除する文字列を入力:"); gets(buf); pos = ListGetPrevPos(header, buf); if (pos == NULL) { printf("\"%s\"は見つかりません\n", buf); } else { ListDelete(pos); } } break; case 'P': case 'p': ListPrintAll(header); break; case 'E': case 'e': ListDestroy(header); exit(0); break; default: printf("(A)dd, (I)nsert, (D)elete, (P)rint, (E)xit\n"); } } return 0;

}

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

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

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

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

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

guest

回答2

0

双方向リストで検索してみてください

双方向リスト:C言語入門

といったページが見つかると思います。言語が異なっても考え方が重要ですので上記のサイト以外にも色々探してみてください。自分はwikipediaの説明が図入りで分かりやすいと思いました。

Wikipedia:双方向リスト

投稿2016/12/14 08:22

KSwordOfHaste

総合スコア18394

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

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

0

最初に、初めてこのサイトを利用するようなので厳しいことを書きます。
今後はもう少し具体的に直面している問題について記載してください。
「どうしたらいいか?」という漠然とした質問の仕方はこの場では不適切です。
どこに躓いたかをきちんと書きましょう。

では、本題です。
ListInsertとListDeleteの二つの変更は双方向リストとしてやりたいことができてて、良い感じだと思います。
※不具合はまだあるかもしれないけどね …というか あります。

あとはListRevPrintAllを実装するだけですよね。
せっかくListPrintAllメソッドがあるので、これを参考にどのような変更が必要か考えてみてはどうでしょうか。

C

1void ListPrintAll(PCELL header) 2{ 3 puts("- addr -- next -:string"); 4 printf("[%08x][%08x]:HEADER\n", header, header->next); 5 header = header->next; 6 while (header) { 7 printf("[%08x][%08x]:<%s>\n", header, header->next, header->string); 8 header = header->next; 9 } 10 puts("------"); 11}

この関数は、先頭のデータを受け取って、次のデータがなくなるまで画面に文字列を表示しています。
ということは、必要なのは…

  • ListPrintAllは先頭データをもらっているので、末尾のデータを貰うこと。

末尾のデータをどうやって指定するのかを考えましょう。

  • 次のデータに向かっていくのではなく、前のデータに戻るようにする。

こんな感じでどうでしょう。作っていけそうですか?

投稿2016/12/14 11:01

haru666

総合スコア1591

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

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだベストアンサーが選ばれていません

会員登録して回答してみよう

アカウントをお持ちの方は

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問