Cプログラミング演習 第10回 二分探索木.

Slides:



Advertisements
Similar presentations
アルゴリズムとデータ構造 第2回 線形リスト(復習).
Advertisements

基本情報技術概論 I 演習(第5回) 埼玉大学 理工学研究科 堀山 貴史
アルゴリズムとデータ構造 第8回 ソート(3).
第10回 整列 ~ バブルソート,挿入ソート,選択ソート~
2分探索.
第11回 整列 ~ シェルソート,クイックソート ~
アルゴリズムとデータ構造 2013年6月18日
アルゴリズムとデータ構造1 2005年7月8日
アルゴリズムとデータ構造 2010年7月5日
基礎プログラミングおよび演習 第9回
データ構造とプログラミング技法 (第8回) ーデータの探索ー.
アルゴリズムとデータ構造 2012年6月14日
情報工学概論 (アルゴリズムとデータ構造)
データ構造とアルゴリズム 第7回 木 ~ データ構造(3)~.
情報工学概論 (アルゴリズムとデータ構造)
データ構造とアルゴリズム 第13回 スタックとキュー
アルゴリズムとデータ構造 第2回 線形リスト(復習その2).
大岩 元 慶応大学環境情報学部 二分木 データ構造とプログラミング(10) 大岩 元 慶応大学環境情報学部
アルゴリズムとデータ構造 2011年6月14日
アルゴリズムとデータ構造 第7回探索のためのデータ構造(1) 2015/11/18 アルゴリズムとデータ構造 2015.
二分探索木によるサーチ.
Cプログラミング演習 中間まとめ2.
茨城大学 工学部 知能システム工学科 井上 康介 E2棟801号室
アルゴリズムとデータ構造 2012年6月28日
アルゴリズムとデータ構造 2011年6月27日
Cプログラミング演習 第7回 メモリ内でのデータの配置.
アルゴリズムとデータ構造1 2006年7月4日
離散数学 08. グラフの探索 五島.
1 T 行きがけ順: A B D F I J C G H 通りがけ順: D B I F J A G C H
アルゴリズムとデータ構造1 2006年6月16日
二分木のメソッド(続き).
木の走査.
アルゴリズムとデータ構造勉強会 B+tree.
アルゴリズムとデータ構造勉強会 第6回 スレッド木
二分探索木における要素削除 データ構造とプログラミング(10)
第9回 優先度つき待ち行列,ヒープ,二分探索木
データ構造と アルゴリズム 第七回 知能情報学部 新田直也.
データ構造と アルゴリズム 第六回 知能情報学部 新田直也.
データ構造と アルゴリズム 第五回 知能情報学部 新田直也.
離散数学 07. 木 五島.
基本情報技術概論(第6回) 埼玉大学 理工学研究科 堀山 貴史
プログラミング 4 整列アルゴリズム.
アルゴリズムとデータ構造 2010年7月26日
プログラミング 4 木構造とヒープ.
簡易データベース 情報画像工学実験 I : 実験2 担当:関屋大雄(工学部1号棟515室)
15.cons と種々のデータ構造.
データ構造とアルゴリズム 第11回 リスト構造(1)
アルゴリズムとデータ構造 第3章 ヒープ 5月31日分
アルゴリズムとデータ構造 第3章 ヒープ 5月31日分の復習
情報数理Ⅱ 第11章 データ構造 平成29年1月18日.
データ構造とアルゴリズム (第5回) 静岡大学工学部 安藤和敏
AVL木.
第9回 優先度つき待ち行列,ヒープ,二分探索木
アルゴリズムとデータ構造 2012年7月2日
アルゴリズムとデータ構造1 2008年7月24日
アルゴリズムとデータ構造 2011年6月28日
アルゴリズムとデータ構造 2011年6月16日
アルゴリズムとデータ構造 2013年7月1日
基本情報技術概論(第6回) 埼玉大学 理工学研究科 堀山 貴史
情報工学概論 (アルゴリズムとデータ構造)
アルゴリズムとデータ構造1 2009年7月2日
アルゴリズムとデータ構造 2013年7月2日
アルゴリズムとデータ構造 補足資料11-3 「線形リストのオペレータ」
ネットワーク・プログラミング Cプログラミングの基礎.
アルゴリズムとデータ構造 第2章 リスト構造 5月24日分
ヒープソート.
アルゴリズムとデータ構造 2013年6月20日
Cプログラミング演習 ニュートン法による方程式の求解.
7.木構造 7-1.データ構造としての木 7-2.2分探索木 7-3.高度な木.
Ibaraki Univ. Dept of Electrical & Electronic Eng.
Presentation transcript:

Cプログラミング演習 第10回 二分探索木

例題1.リストの併合 2つのリストを併合するプログラムを動かしてみる head1 head2 tail1 tail2 head1 tail1    NULL    NULL tail1 があると,リストの併合に便利 head1 tail1    NULL

tail1->next = head2; tail1 = tail2; #include "stdafx.h" #include <math.h> struct data_list { int data; struct data_list *next; }; void print_list(struct data_list *p) { struct data_list *x; if ( p == NULL ) { return; } printf( "%d", p->data ); x = p->next; while( x != NULL ) { printf( ", %d", x->data ); x = x-> next; printf( "\n" ); struct data_list *new_list(int x) struct data_list *c = new(struct data_list); c->data = x; c->next = NULL; return c; void insert_list(struct data_list *p, int x) c->data = p->data; c->next = p->next; p->data = x; p->next = c; int _tmain() int ch; struct data_list *head1; struct data_list *tail1; struct data_list *head2; struct data_list *tail2; head1 = new_list( 6789 ); insert_list( head1, 45 ); tail1 = head1->next; // 2個目の要素を作った時点で head1->next と tail1 が等しい insert_list( head1, 123 ); head2 = new_list( 789 ); insert_list( head2, 56 ); tail2 = head2->next; // 2個目の要素を作った時点で head2->next と tail2 が等しい insert_list( head2, 1234 ); printf( "併合前\n" ); print_list( head1 ); print_list( head2 ); // tail1->next = head2; tail1 = tail2; printf( "併合後\n" ); printf( "Enter キーを1,2回押してください. プログラムを終了します\n"); ch = getchar(); return 0; tail1->next = head2; tail1 = tail2;

実行結果の例

二分探索木 (binary search tree) 整列可能な任意個数のデータ集合に対し、効率良い探索(二分探索)を行うためのデータ構造 整列前:35 46 21 13 61 40 69 整列後(昇順):13 21 35 40 46 61 69 節点から出る枝が高々2本の木構造(二分木)を作り、各節点にデータを置く

二分探索木の構造 節点(node)と枝(branch) 枝はデータ間の(親子)関係を表す 節点に入る(親からの)枝は1本 節点から出ていく(子への)枝は0または1または2本 親 親 節点(node) 枝(branch) 子 子 子

二分探索木の構造(つづき) 根(root): 親を持たない節点 葉(leaf): 子を持たない節点 部分木(subtree): 任意の節点から下のすべての枝と節点 部分木(subtree) 根(root) 葉(leaf)

二分探索木の再帰的構造 左部分木、右部分木も二分木をなす 親節点に対する処理が、子節点に対する処理に帰着されることが多い (例)探索において,子へ移動し,親での処理と      同様の処理を繰り返す →再帰関数を用いて自然に表現できる。 左部分木 右部分木 左部分木 右部分木

二分探索木の各ノードを C言語の構造体で表現 value // 2分木のノード struct BTNode {   BTNode *left;   BTNode *right; int value; }; 1個の 構造体 left right value value left right left right int value の部分は,格納 すべきデータに応じて変わる

二分探索木の節点(node) の 生成関数 new_node #include "stdafx.h" #include <math.h> struct BTNode { BTNode *left; BTNode *right; int value; }; struct BTNode *new_node(int x, struct BTNode *y, struct BTNode *z) struct BTNode *w = new BTNode(); w->value = x; w->left = y; w->right = z; return w; } int _tmain() int ch; BTNode *root; root = new_node( 100, NULL, NULL ); printf( "Enter キーを1,2回押してください. プログラムを終了します\n"); ch = getchar(); return 0; メンバ value, left, right に値をセット 例題2,3,4で使用

例題2.二分探索木の生成 データの配置のしかた 左側のすべての子は親より小さく 右側のすべての子は親より大きく 35 21 13 40 61 46 69 new_node を7回呼び出して,節点を7個作る

in-order で要素を表示 (in-order については後述) 2分木の生成 #include "stdafx.h" #include <math.h> struct BTNode { BTNode *left; BTNode *right; int value; }; void print_data( struct BTNode *root ) if ( root->left != NULL ) { print_data( root->left ); } printf( "%d\n", root->value ); if ( root->right != NULL ) { print_data( root->right ); struct BTNode *new_node(int x, struct BTNode *y, struct BTNode *z) struct BTNode *w = new BTNode(); w->value = x; w->left = y; w->right = z; return w; int _tmain() int ch; BTNode *root; root = new_node( 35, new_node( 21, new_node(13, NULL, NULL), NULL), new_node( 46, new_node(40, NULL, NULL), new_node(61, NULL, new_node(69, NULL, NULL)))); print_data( root ); printf( "Enter キーを1,2回押してください. プログラムを終了します\n"); ch = getchar(); return 0; in-order で要素を表示 (in-order については後述) 2分木の生成

実行結果の例

in-order での表示 最初に左部分木 次に自分(節点) 最後に右部分木 35 21 13 40 61 46 69 void print_data( struct BTNode *root ) { if ( root->left != NULL ) { print_data( root->left ); } printf( "%d\n", root->value ); if ( root->right != NULL ) { print_data( root->right ); in-order での表示 最初に左部分木 次に自分(節点) 最後に右部分木 35 21 13 40 61 46 69

例題3.二分探索木における探索 指定された要素が存在するかを探す 40 → 有り 41 → 無し 35 21 13 40 61 46 69

二分探索木における探索 根(root)から始める。 探索キーの値と,各節点のデータを比較し目標となるデータを探す 探索キーよりも節点のデータが小さいときは,右側の子に進む 探索キーよりも節点のデータが大きいときは,左側の子に進む

探索の例 (例) 節点40を探す場合 根の値(35)と,探索キー(40)を比較 探索キーの方が大きいので,右側の子節点へ移る 次に移った節点の値(46)と探索キー(40)を比較し 探索キーの方が小さいので,左の子節点へ移る 次に移った節点(40)が,目標の節点である 35 21 13 40 61 46 69

探索(見つからなければ NULL を返す) 2分木の生成 #include "stdafx.h" #include <math.h> struct BTNode { BTNode *left; BTNode *right; int value; }; struct BTNode *find_node(int x, struct BTNode *root) BTNode *node; node = root; while( ( node != NULL ) && ( x != node->value ) ) { if ( x < node-> value ) { node = node->left; } else { node = node->right; return node; struct BTNode *new_node(int x, struct BTNode *y, struct BTNode *z) struct BTNode *w = new BTNode(); w->value = x; w->left = y; w->right = z; return w; int _tmain() int ch; BTNode *root; BTNode *y; root = new_node( 35, new_node( 21, new_node(13, NULL, NULL), NULL), new_node( 46, new_node(40, NULL, NULL), new_node(61, NULL, new_node(69, NULL, NULL)))); y = find_node( 40, root ); if ( y == NULL ) { printf( "40 は無し\n" ); printf( "40 は有り\n" ); printf( "Enter キーを1,2回押してください. プログラムを終了します\n"); ch = getchar(); return 0; 探索(見つからなければ NULL を返す) 2分木の生成

探索を行う関数 struct BTNode *find_node(int x, struct BTNode *root) { BTNode *node; node = root; while( ( node != NULL ) && ( x != node->value ) ) { if ( x < node-> value ) { node = node->left; } else { node = node->right; return node;

実行結果の例

例題4.二分探索木への挿入 要素の挿入を行う関数を作る 35 46 21 13 61 40 69 を挿入すると, 例題1と同じ二分探索木ができる 35 21 13 40 61 46 69

二分探索木への挿入 二分探索木に新たなデータを挿入する 挿入すべき位置を探す (find_nodeと同じ要領) 新たな節点を生成 挿入位置として見つかった節点において、新たな節点をポイントするようにポインタを書き換える

最初は,節点を1個含む二分探索木を作り, その後,残りの要素を挿入する #include "stdafx.h" #include <math.h> struct BTNode { BTNode *left; BTNode *right; int value; }; void print_data( struct BTNode *root ) if ( root->left != NULL ) { print_data( root->left ); } printf( "%d\n", root->value ); if ( root->right != NULL ) { print_data( root->right ); struct BTNode *new_node(int x, struct BTNode *y, struct BTNode *z) struct BTNode *w = new BTNode(); w->value = x; w->left = y; w->right = z; return w; struct BTNode *insert_node(struct BTNode *node, int x) if ( node == NULL ) { return new_node(x, NULL, NULL); else if ( x < node->value ) { node->left = insert_node(node->left, x); return node; else if ( x > node->value ) { node->right = insert_node(node->right, x); else { int _tmain() int ch; BTNode *root; root = new_node( 35, NULL, NULL ); insert_node( root, 46 ); insert_node( root, 21 ); insert_node( root, 13 ); insert_node( root, 61 ); insert_node( root, 40 ); insert_node( root, 69 ); print_data( root ); printf( "Enter キーを1,2回押してください. プログラムを終了します\n"); ch = getchar(); return 0; 最初は,節点を1個含む二分探索木を作り, その後,残りの要素を挿入する

挿入を行う関数 struct BTNode *insert_node(struct BTNode *node, int x) { if ( node == NULL ) { return new_node(x, NULL, NULL); } else if ( x < node->value ) { node->left = insert_node(node->left, x); return node; else if ( x > node->value ) { node->right = insert_node(node->right, x); else {

実行結果の例

木の踏査 (tree traversal) 一定の手順で木の各節点を訪れ、処理を行う 3とおりの手順 処理の内容によって使い分ける pre-order traversal (行きがけ順) post-order traversal (帰りがけ順) in-order traversal (通りがけ順) 処理の内容によって使い分ける

通りがけ順 (in-order traversal) 左の子節点以下を処理 (左部分木を辿る) 親節点について処理 (根を辿る) 右の子節点以下を処理 (右部分木を辿る) ②根を辿る A B C D E F G D, B, E, A, F, C, G の順に処理を行う ①左部分木を辿る ③右部分木を辿る

帰りがけ順 (post-order traversal) 左の子節点以下を処理 右の子節点以下を処理 親節点について処理 A B C D E F G D, E, B, F, G, C, A の順に処理を行う

通りがけ順 (in-order traversal) 左の子節点以下を処理 親節点について処理 右の子節点以下を処理 A B C D E F G D, B, E, A, F, C, G の順に処理を行う