• Tidak ada hasil yang ditemukan

3 リスト (List) 構造の設計と実装 (続き)

N/A
N/A
Protected

Academic year: 2024

Membagikan "3 リスト (List) 構造の設計と実装 (続き)"

Copied!
6
0
0

Teks penuh

(1)

3 リスト (List) 構造の設計と実装 ( 続き )

関数 print list() を呼出す側も含め て、正しく動作するプログラムを完成し、

この実習時間中にレポートとして提出 せよ。

課題 2 (10/14出題). 先の例(実習3.1)で、リストの走査(表示)の部分を関数 print list() として関数 化せよ。

返値を void(値を返さない) とせず、例 えばint 返しとして、表示した個数 (つ まりリストの長さ) を返させることなど も 考 え ら れ る 。返 さ せ て お い て 使 わ な くても別に構わない。実際、実は例えば printf()もintを返している。(返して いる値は何か?)

解答例 2.1. 関数 print list() の部分のみ示す。

/* list0.c 2008-10-14 */

/* print_list() ver.1 */

void print_list(Node *t) /* printing list */

{

while( t->next != NULL ) {

t = t->next;

printf(" -> %d", t->val);

}

printf(".\n");

return;

}

解答例 2.2. 前ページ下方の方針で、次のようにすることも出来る。

/* list0.c 2008-10-14 */

/* print_list() ver.2 */

void print_list(Node *t) /* printing list */

{

while( t != NULL ) {

printf(" -> %d", t->val);

t = t->next;

}

printf(".\n");

return;

}

それぞれの場合について、呼出し側で何を引数として呼べば良いか。

(2)

3–4 リストからの節点の削除

リスト構造の大きな利点は、リストの途中に新たな節点を挿入したり、リストの途中の節点を削除したり、

という操作が便利にできることである。

既存のリストから節点を削除するには、その手前の節点とその次の節点とを繋いでしまえばよろしい。その

要領は次の通り。 実はこれは完全版ではない。削除した節

点のメモリ領域が確保されたまま残って しまっている (ばかりか、それなのに決 してアクセスできない状態になっている) からである。領域確保と削除とを頻繁に 行なう場合には致命的な欠陥となり得る。

これをメモリリーク(memory leak)と いう。その対処も含めた完全版は後述。

(1) 削除したい節点の手前の節点に、追跡用ポインタを向ける。

(2) 追跡用ポインタの指す節点の次の節点(つまり削除したい節点)の次の節点に、追跡用ポインタの指す節 点(つまり削除したい節点の手前の節点)の次へのリンクを向ける。

target

3: リストからの節点の削除

. 節点 *p の次の節点を削除する関数delete Node() の実装の暫定版。 これだけだと関数にするまでもないが、

後でメモリリークの対処まで含めたもの にする予定で、関数化しておく。

void delete_Node( Node *p ) {

p->next = p->next->next;

return;

}

実習 3.2. 実習3.1の要領で、入力した整数を各節点の値とするリストを作成・表示した後で、整数値を一 つ入力し、それより大きい値を持つ節点を全てリストから削除した後、削除後のリストを辿って全ての値を順 に表示するプログラム。(次頁)

(3)

while 文の条件式の所にコンマ演算子 , を使ってみた。, で区切って並べた式を 左から順次評価し、最後(一番右)に評価 した式の値が、コンマ演算子で結合され た式の値となる。濫用すると見難くもな るが、便利な場合が時々ある。ここでは 実感に合い、自然であろう。

節点を削除した時には target=target->next;

を実行してはいけないことを確認しよう。

「動作確認のすすめ」

途中を削除

先頭を削除

末尾を削除

全部削除

一つも削除しない

など、様々な状況で動作確認せよ。

/* list1.c 2008-10-21 */

#include <stdio.h>

#include <stdlib.h>

typedef struct node { int val;

struct node *next;

} Node;

void print_list( Node * );

void delete_Node( Node * );

int main( int argc, char **argv ) {

int a;

Node head, *target;

target = &head;

while( scanf("%d",&a), a != 0 ) {

target->next = (Node *)malloc(sizeof(Node));

target = target->next;

target->val = a;

}

target->next = NULL;

print_list(&head);

/* delete if val is greater than a */

scanf("%d",&a);

target = &head;

while( target->next != NULL ) {

if ( target->next->val > a ) delete_Node(target);

else

target = target->next;

}

print_list(&head);

return 0;

}

関数print list() は各自作ったものを、delete Node()は前頁のものを利用せよ。

(4)

3–5 動的確保したメモリの解放

本小節は純粋にデータ構造という点では 本質的でないが、データがどのように計 算機上で扱われているか、という点も含 め、実際のプログラミングに於いては重 要である。

前節の例(実習3.2)では、節点をリストから削除したと言っても、リストの先頭から辿って到達できなく なっただけで、その節点のメモリ領域は確保されたままで、変数領域として使用中ということになっている。

従って、次にメモリの動的確保をする場合には、この領域は使われない。大量のデータを扱い、領域確保と削 除とを頻繁に行なう場合には、この領域を再利用したい。その為には「この領域はもう使っていないので次の 動的確保で使ってもよろしい」という領域解放の手続きが必要である。それには関数 free() を用いる。基本

形は次の通り。p をポインタ変数とし、その指す領域が malloc() (など)で動的確保されているとする。 プロトタイプは stdlib.h に記述されて いる。malloc() を使うのに呼んでいる だろうからそれでよい。

void free(void *)

ここでの void *型は汎用ポインタ型で、

どんな型へのポインタでも良い。

free(p);

free() で解放する領域は動的確保され

たメモリ領域に限る。例えば int a;

free(&a);

は不可。

free() の引数の値が NULL なら何もし ない。(エラーではない。)

. 節点 *p の次の節点を削除する関数delete Node() の実装で、削除した節点の領域を解放し、メモリ リークの対処を含めたもの。

void delete_Node( Node *p ) {

Node *t;

t = p->next;

p->next = t->next;

free(t);

return;

}

前の例のように先に p->next = p->next->next としてしまうと、解放すべき領域を指すポインタがなく なってしまい、もはやその領域にアクセスすることが出来ない(従って領域解放も出来ない)。そこでそれを一 時的に覚えておく為の変数が必要となることに注意しよう。

(5)

. このように見てくると、節点へのポインタ Node *型の方が頻繁に現れがちなことに気付く。そこで、

節点へのポインタ型の方を、例えば Link 型として、別名定義して扱う方針にすると、次のような型定義・初

期化処理になる。 先頭にダミー節点を置き、末尾をNULLに

する流儀の場合。*head がダミー節点と typedef struct node *Link; なる。

struct node { int val;

Link next;

};

int main( int argc, char **argv ) {

Link head, target;

head = (Link)malloc(sizeof(struct node));

head->next = NULL;

...

}

演習は、期限までの提出を義務とする課 題ではないが、内容が良ければ成績評価 に反映させる、一種の研究課題である。

積極的に取り組むことを望む。

提出の際の Subjectは、Exercise1等と すれば良い。

演習 1. 上記のように節点へのポインタ型の方を通常扱う型として(つまり typedef struct node *Link と別名定義して) 扱う方針に変更して、今までの全てのプログラムを書き換えるとどうなるか。また、今後の 課題についても適宜判断して便利な方を用いて書け。

演習 2 (Josephusの問題・継子立て). 2 つの自然数 n, k に対して、次のようなゲーム風の動作を実行し て結果(並びに途中経過)を表示するプログラムjosephus.c を作成せよ。

(1) 1 番からn 番までの n 人が番号順に車座になる。(n 番の人の次が 1 番に戻る。)

(2) 1 番の人から数えていって k 番目の人が抜ける。(従って k ≤n なら k 番の人、k > nなら 2 巡目以 降。) 抜けた場所は詰める。

(3) 残った人の中で、抜けた人の次の人から数えていって k 番目の人が抜け、抜けた場所は詰める。

(4) 以下、これを繰返して最後まで残った 1 人が勝ち。

(6)

3–6 リストへの節点の挿入

既存のリストの途中への新たな節点の挿入も、ポインタの繋ぎ替えにより、次の要領で容易に出来る。 この操作が挿入箇所の前後だけの処理で 高速に出来る点が重要。

(1) 挿入したい場所の手前の節点に、追跡用ポインタを向ける。

先頭への挿入の場合、「手前の節点」とは ダミーの節点。また、末尾への挿入 (追 加)の場合、「次」は NULL である。これ らの場合に例外処理は必要であるか。

(2) 追跡用ポインタの指す節点の次へのリンクが指す節点(つまり挿入したい場所の次の節点)を一時記憶 用ポインタに記憶する。

(3) 挿入する節点の領域をmalloc()で確保し、その返値(つまり今確保した節点へのポインタ)を、追跡用 ポインタの指す節点の次へのリンクに代入する(つまり次へのリンクを今確保した新節点に向ける)。 (4) 一時記憶用ポインタが指す節点(つまり挿入したい場所の次の節点)に、新節点の次へのリンクを向

ける。

target tmp

4: リストへの節点の挿入

今回の課題は 1 週余裕を見て次々回の授 業前日までとする。

課題 3 (〆切 11/3()). リストを用いて、次々と入力した整数値を大きさの順に並べ替えて表示するプロ

グラム list2.c を作成せよ。 入力データ数を n 個(充分大)とする時、

比較の回数は如何程と見積もれるか。

最大で

平均で

入力した整数を値とする新節点を、リストの適切な場所に挿入し、作成したリストの各節点の値が大き さの順になるようにする。

0 が入力されたら終了。(0 を値とする節点は作らない。)

先頭からリストを辿って全ての値を順に表示する。

Referensi

Dokumen terkait

はじめに 触媒活性を持つ RNA(リボザイム)や RNA干渉の発見によ り,RNA が遺伝子の発現調節において重要な役割を担ってい ることが明らかになっている.これらの機能性RNA は,多く の場合RNA のみでは活性を示さず,タンパク質と複合体(リ ボ核タンパク質)を形成することにより機能している.従っ て,機能性RNA の作用機構を理解するためには,タンパク質

〈研究ノート〉 移動式簡易炭焼き窯の製造と流木炭化の実証実験 佐藤 司 1. はじめに 平成 22~23 年度にかけて山形県庄内総合支庁 より委託を受けて海岸漂着ゴミの再資源化 に関 する調査研究を実施してきた 1, 2.その中で流木 の漂着が近年顕著になっていることが次第 に明 らかになってきた.平成 20 年度の報告によると,

特 集 新型コロナ禍における 廃棄物処理事業の継続のために 特 集 新型コロナ禍における 廃棄物処理事業の継続のために 秩ちち父ぶ 薫しげ雅のり 一般社団法人 日本環境衛生施設工業会 技術委員 1.はじめに 廃棄物処理は生活・経済の安定維持のた めに不可欠であり、さらにごみ焼却施設は エネルギー供給拠点、防災拠点として重要

257 も の づ く り 創 造 卒業研修 (必修 4 単位) 2年前後期 ものづくり創造工学科教員 授業テーマ・内容 ものづくり創造工学科における学修の締めくくりとして、研究・研修グループに所属し、指導教員の指導のもとで特定のテーマについ

日本人の装いと梅 日本人の装いと梅 寺田 朋代 (山崎芙紗子ゼミ) はじめに

2 (2)会計利益に基づく報酬制度を採用する会社の特徴 調査によると、採用する割合が業種によって異なる (Conference Board,1979) 例:小売業よりも製造業のほうがボーナス制度を採用して いる会社の割合が大きい 理由: インセンティブ仮説 他の条件が等しければ、利益額と、特定の経営者の行動が会

・B4の用紙で印刷してください。 ・点線で切ると実際の大きさになります。 サミングとは,親指で裏穴(サム ホール)の開きぐあいを操作すること です(数字は ,記号は で表します)。 サミングにはAと Bのように二つの 方法があります。Aは親指を少しずら す方法,Bは爪つめを立てる(第一関節を 曲げる)方法です。サミングを必要と

2 3.2 センサー部 曲げセンサーは約 10kΩの抵抗を持つが,センサー自身を曲げると曲げた量に比例して約 30kΩ まで抵抗が増加する.この性質を利用して図2のセンサー回路を製作すると,Voから抵抗の変化に 比例した電圧が計測できる.曲げセンサーが曲がっていない状態ではVo=2.5Vである.曲げセンサ