AVL木の実装で困っています

フォーラム(掲示板)ルール
フォーラム(掲示板)ルールはこちら  ※コードを貼り付ける場合は [code][/code] で囲って下さい。詳しくはこちら
RIKU13

AVL木の実装で困っています

#1

投稿記事 by RIKU13 » 8年前

以下のようなAVL木のコードを書いてみたのですがセグメンテーション違反が出てしまい原因が分からず困っています。
内容としては、ある数列をAVL木として挿入を行い、数列の数が50個までの場合は可視化を行っています。初心者であるため、かなり煩雑なコードになっていますが、アドバイスお願いいたします。なるべく早く返信を頂けると幸いです。
私の予想としてはinsert_nodeとrebalanceの中身でミスをしているのではないかという検討を立てています。
code=C
#include<stdio.h>
#include<stdlib.h>
#include<math.h>
#include<time.h>
#define VISION 50
#define AVL_BALANCED 0
#define AVL_LEFT 1
#define AVL_RIGHT 2

typedef struct node{
struct node *left;
struct node *right;
struct node *parent;
int element;
int balance;
}Node;

typedef struct{
Node *root;
}Tree;

static void destroy_node(Node *node)
{
if (node != NULL){
destroy_node(node->left);
destroy_node(node->right);
free(node);
}
}

void rebalance(Node *node, int direct)
{
Node *prev,*next;

if (node == NULL) return;
if ((node->balance == AVL_LEFT && direct == AVL_RIGHT)
|| (node->balance == AVL_RIGHT && direct == AVL_LEFT))
{
node->balance = AVL_BALANCED;
} else if (node->balance == AVL_BALANCED) {
node->balance = direct;
if ((prev = node->parent) != NULL)
rebalance(prev, node->element < prev->element ? AVL_LEFT : AVL_RIGHT);
} else if (node->balance == direct){
prev = node->parent;
if (node->left->balance == direct) {
next = (direct == AVL_LEFT) ? node->left : node->right;
node->parent = next;
next->parent = prev;
if (direct == AVL_LEFT) {
node->left = next->right;
next->right = node;
} else {
node->right = next->left;
next->left = node;
}
node->balance = AVL_BALANCED;
next->balance = AVL_BALANCED;
} else {
Node *dene;
if (direct == AVL_LEFT) {
dene = node->left;
next = dene->right;
} else {
dene = node->right;
next = dene->left;
}

node->parent = next;
dene->parent = next;
next->parent = prev;
if (direct == AVL_LEFT) {
node->left = next->right;
next->right = node;
dene->right = next->left;
next->left = dene;
dene->balance = (next->balance == AVL_RIGHT) ?
AVL_LEFT : AVL_BALANCED;
node->balance = (next->balance == AVL_LEFT) ?
AVL_RIGHT : AVL_BALANCED;
} else {
node->right = next->left;
next->left = node;
dene->left = next->right;
next->right = dene;
dene->balance = (next->balance == AVL_LEFT) ?
AVL_RIGHT : AVL_BALANCED;
node->balance = (next->balance == AVL_RIGHT) ?
AVL_LEFT : AVL_BALANCED;
}
next->balance = AVL_BALANCED;
}
if (prev->parent == NULL)
prev->left = prev->right = next;
else if (node->element < prev->element) prev->left = next;
else prev->right = next;
}
}
static Node *make_node(int element,Node *prev)
{
Node *node = malloc(sizeof(Node));
if (node != NULL){
node->element=element;
node->left=NULL;
node->right=NULL;
node->balance = 0;
node->parent = prev;
}
return node;
}
static Node *insert_node(int element,Node *node)
{
Node *prev = NULL;

while (node != NULL) {
if (element == node->element) return NULL;
prev = node;
if (element < node->element)
node->left = insert_node(element,node->left);
else
node->right = insert_node(element,node->right);
}
make_node(element,prev);
if (prev != NULL)
rebalance(prev, element < prev->element ? AVL_LEFT : AVL_RIGHT);
return node;

}

int depth_node(int element,Node *node)
{
int depth = 0;
while(node->element != element){
if(element < node->element){
node = node->left;
}else{
node = node->right;
}
depth++;
}
return depth;
}

int depth_tree(int element,Tree *tree)
{
return depth_node(element,tree->root);
}

Tree *make_tree(void)
{
Tree *tree = malloc(sizeof(Tree));
if (tree != NULL){
tree->root = NULL;
}
return tree;
}

void insert_tree(int elememt,Tree *tree)
{
tree->root = insert_node(elememt,tree->root);
}

void destroy_tree(Tree *tree)
{
destroy_node(tree->root);
free(tree);

}

int GetRandom(int min,int max)
{
return min + (int)(rand()*(max-min+1.0)/(1.0+RAND_MAX));
}

void shuffle(int *num,int n)
{
int s,m,tmp;
for(s = n - 1;s > 0;s--){
m = rand() % (s + 1);
tmp = num;
num = num[m];
num[m] = tmp;
}
}
int main(void)
{
int i,n,x,y,z,tree_number,*num,(*vision)[VISION],
depth,height,error,*height_tree;
double sum_height=0,sum2_height=0,real_number=0,average1,average2;

srand((unsigned int)time(NULL));

printf("!!");
fflush(0);
scanf("%d",&n);

int (*check_tree)[n];

tree_number = (int)((double)n/log2((double)n));
num = calloc(n,sizeof(int));
check_tree = calloc(tree_number * n,sizeof(int));
height_tree = calloc(n,sizeof(int));

for (i = 0;i < n;i++)
num=i+1;
for(x = 0;x < tree_number;x++){
Tree *tree =make_tree();
if(n <= VISION)
vision = calloc(VISION * VISION,sizeof(int));
height = 0;
error = 0;
shuffle(num,n);
for (i = 0;i < n;i++){
insert_tree(num,tree);
if(n <= VISION)
printf("%d ",num);
}
for(i = 0;i < n;i++){
depth=depth_tree(num,tree);
if(n <= VISION)
vision[depth][num-1]=num;
if(depth >= height)
height = depth;
check_tree[x][num-1]=depth;
}

for(y = 0;y < x;y++){
for(z = 0;z < n;z++){
if(check_tree[y][z]!=check_tree[x][z])
break;
}
if((z == n)&&(check_tree[y][z-1]==check_tree[x][z-1])){
error++;
break;
}
}
if(x != 0&&error == 1){
printf("this tree has been already created\n");
if(n <= VISION)
free(vision);
destroy_tree(tree);
continue;
}
if(n <= VISION){
printf("\n");
for(y = 0;y <= height;y++){
for(z = 0;z < n;z++){
if(vision[y][z] != 0)
printf("%2d",vision[y][z]);
else
printf(" ");
}
printf("\n");
}
printf("%d\n",height);
}
if(n <= VISION)
free(vision);
destroy_tree(tree);
height_tree[height]++;
}
for(i = 0;i < n;i++){
sum_height += (i * height_tree);
sum2_height += (i * i * height_tree);
real_number += height_tree;
}
average1 = sum_height / tree_number;
average2 = sum2_height /tree_number;

printf("%f\n%f\n",average1,average2 - average1 * average1);
free(check_tree);
free(height_tree);
return 0;
}
/code

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

Re: AVL木の実装で困っています

#2

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

insert_node関数内でmake_node関数の返り値を捨てているため、メモリリークが発生します。
さらに、初期状態ではnode、すなわちtree->rootはNULLなのでnodeの操作をするコードは実行されず、
insert_nodeを呼び出してもtree->rootがNULLのまま更新されません。
また、prevもNULLなのでrebalance関数は呼び出されません。

その後depth_tree関数を呼び出すと、NULLであるtree->rootがdepth_node関数にnodeとして渡され、
node->element != elementという条件式でNULLがデリファレンスされ、未定義動作になります。
この結果、アクセス違反が発生するかもしれません。
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)

RIKU13

Re: AVL木の実装で困っています

#3

投稿記事 by RIKU13 » 8年前

みけCATさん丁寧な解説ありがとうございます。
いろいろな参考を見ながら今回のソースを書いたためにあまり深い理解ができずに書いてしまいました。

もし、よろしければ手直しするところや改善点を教えてくださると助かります。

RIKU13

Re: AVL木の実装で困っています

#4

投稿記事 by RIKU13 » 8年前

make_nodeの返り値を捨ててしまっていたため、return make_nodeに 変更したところ違反は出ませんでしたが、実行はされませんでした。

Math

Re: AVL木の実装で困っています

#5

投稿記事 by Math » 8年前

私の環境ではエラーがでます。コードが見にくいしコメントがないのは可読性にかけます。私の双方向リストはコマンドライン・コンパイルが通ります。

コード:

//-----------------------------------------------------------------------------
#include <stdio.h>    // for printf   -
#include <stdlib.h>  // for malloc
//-----------------------------------------------------------------------------
typedef struct ns {
	int data;        //構造体のデータ
	struct ns *next;//構造体のポインター
} node;
//-----------------------------------------------------------------------------
node *list_add(node **p, int i) {    // add head
    node *n = malloc(sizeof(node)); // you normally don't cast a return value for malloc
    n->next = *p;                  // 次ポインターの代入
    *p = n;               
    n->data = i;
    return n;
}
//-----------------------------------------------------------------------------
node *list_add_tail(node **p, int i) { // add tail 
    node *n;
    node *ptr;
    if (*p == NULL) {
        n = list_add(p, i);
    } else {
        ptr = *p;
        while (ptr->next != NULL) {
            ptr = ptr->next;
        }
        n = malloc(sizeof(node));
        n->next = NULL;
        n->data = i;
        ptr->next = n;
    }
    return n;
}
//-----------------------------------------------------------------------------
void list_remove(node **p) { // remove head
    if (*p != NULL) {
        node *n = *p;
	*p = (*p)->next;
	free(n);
    }
}
//-----------------------------------------------------------------------------
void list_remove_tail(node **p) { // remove tail
    if (*p != NULL) {	
        if( (*p)->next == NULL ) {
            list_remove(p);
        } else {
            node *ptr = *p;	
            node *pre;
            while (ptr->next != NULL) {
                pre = ptr;
                ptr = ptr->next;
            }
            pre->next = NULL;
            free(ptr);
        }
    }
}
//-----------------------------------------------------------------------------
void list_remove_all(node **p) { // remove all node
    while (*p != NULL) {
        list_remove(p);
    }
}
//-----------------------------------------------------------------------------
node **list_search(node **n, int i) {
    while (*n != NULL) {
        if ((*n)->data == i) {
            return n;
        }
        n = &(*n)->next;
    }
    return NULL;
}
//-----------------------------------------------------------------------------
void list_print(node *n) {
    if (n == NULL) {
        printf("list is empty\n");
    }
    while (n != NULL) {
        printf("print %p %p %d\n", n, n->next, n->data);
        n = n->next;
    }
}
//-----------------------------------------------------------------------------
int main(void) {
    node *n = NULL;
    //----------------------------list_add---STL---Generic---<---not!specific--
    list_add(&n, 0); /* list: 0 */
    list_add(&n, 1); /* list: 1 0 */
    list_add(&n, 2); /* list: 2 1 0 */
    list_add(&n, 3); /* list: 3 2 1 0 */
    list_add(&n, 4); /* list: 4 3 2 1 0 */
    list_print(n);
    list_remove(&n);            /* remove first (4) */
    list_remove(&n->next);      /* remove new second (2) */
    list_remove(list_search(&n, 1)); /* remove cell containing 1 (first) */
    list_remove(&n->next);      /* remove second to last node (0) */
    list_remove(&n);            /* remove last (3) */
    list_print(n);

    return 0;
}
//-----------------------------------------------------------------------------

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

Re: AVL木の実装で困っています

#6

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

Math さんが書きました: 私の双方向リストはコマンドライン・コンパイルが通ります。
どうしていきなりほとんど関係ない双方向リストのプログラムを貼ったのですか?
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)

Math

Re: AVL木の実装で困っています

#7

投稿記事 by Math » 8年前

機種、OS,コンパイラーは何を使ってますか。Windows10、VS2015ではエラーがでます。make_nodeの双方向リストみたいなあたりもおかしかったですよ。

コード:

重大度レベル	コード	説明	プロジェクト	ファイル	行	抑制状態
エラー	C2440	'=': 'void *' から 'int (*)[50]' に変換できません。	ConsoleApplication2	重大度レベル	
エラー (アクティブ)		型 "void *" の値を使用して型 "Node *" のエンティティを初期化すエラー	C2440
エラー	C2440	'初期化中': 'void *' から 'Node *' に変換できません。	ConsoleApplication2	エラー (アクテ
エラー	C2440	'初期化中': 'void *' から 'Tree *' に変換できません。	ConsoleApplication2	エラー	C2440
エラー	C2131	式は定数に評価されませんでした	ConsoleApplication2	c:\users\数彦\documentエラー	C2440
エラー	C2440	'=': 'void *' から 'int *' に変換できません。	ConsoleApplication2	c:\useエラー	C2131
エラー	C2440	'=': 'void *' から 'int (*)[n]' に変換できません。	ConsoleApplication2	エラー	C2440
エラー	C2440	'=': 'void *' から 'int *' に変換できません。	ConsoleApplication2	c:\useエラー	C2440
エラー	C3863	配列型 'int [n]' を割り当てることはできません。	ConsoleApplication2	c:\useエラー	C2440
警告	C4996	'scanf': This function or variable may be unsafe. Consider using scanf_s insteエラー	C3863
警告	C4996	'scanf': This function or variable may be unsafe. Consider using scanf_s insteエラー (アクティ
エラー	C2440	'初期化中': 'void *' から 'Node *' に変換できません。	ConsoleAエラー	C2440	'初期化中': '
エラー	C2440	'初期化中': 'void *' から 'Tree *' に変換できません。	ConsoleAエラー	C2440	'初期化中': '
エラー	C2131	式は定数に評価されませんでした	ConsoleApplication2	c:\usersエラー	C2131	式は定数に評価
エラー	C2440	'=': 'void *' から 'int *' に変換できません。	ConsoleApplicatiエラー	C2440	'=': 'void *'
エラー	C2440	'=': 'void *' から 'int (*)[n]' に変換できません。	ConsoleAエラー	C2440	'=': 'void *'
エラー	C2440	'=': 'void *' から 'int *' に変換できません。	ConsoleApplicatiエラー	C2440	'=': 'void *'
エラー	C3863	配列型 'int [n]' を割り当てることはできません。	ConsoleApplicatiエラー	C3863	配列型 'int [
警告	C4996	'scanf': This function or variable may be unsafe. Consider using警告	C4996	'scanf': This
AVL木、など木構造(リスト構造)はC++/C#の基本にもなるので知りたいと思っていたので調べてみましょう。(ところで何に使われるのですか?)

Math

Re: AVL木の実装で困っています

#8

投稿記事 by Math » 8年前

インデントが全くないととても見にくいです。VisualStudioなら簡単にインデントを直してくれますよ。

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

Re: AVL木の実装で困っています

#9

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

Math さんが書きました:Windows10、VS2015ではエラーがでます。make_nodeの双方向リストみたいなあたりもおかしかったですよ。

コード:

重大度レベル	コード	説明	プロジェクト	ファイル	行	抑制状態
エラー	C2440	'=': 'void *' から 'int (*)[50]' に変換できません。	ConsoleApplication2	重大度レベル	
エラー (アクティブ)		型 "void *" の値を使用して型 "Node *" のエンティティを初期化すエラー	C2440
エラー	C2440	'初期化中': 'void *' から 'Node *' に変換できません。	ConsoleApplication2	エラー (アクテ
エラー	C2440	'初期化中': 'void *' から 'Tree *' に変換できません。	ConsoleApplication2	エラー	C2440
エラー	C2131	式は定数に評価されませんでした	ConsoleApplication2	c:\users\数彦\documentエラー	C2440
エラー	C2440	'=': 'void *' から 'int *' に変換できません。	ConsoleApplication2	c:\useエラー	C2131
エラー	C2440	'=': 'void *' から 'int (*)[n]' に変換できません。	ConsoleApplication2	エラー	C2440
エラー	C2440	'=': 'void *' から 'int *' に変換できません。	ConsoleApplication2	c:\useエラー	C2440
エラー	C3863	配列型 'int [n]' を割り当てることはできません。	ConsoleApplication2	c:\useエラー	C2440
警告	C4996	'scanf': This function or variable may be unsafe. Consider using scanf_s insteエラー	C3863
警告	C4996	'scanf': This function or variable may be unsafe. Consider using scanf_s insteエラー (アクティ
エラー	C2440	'初期化中': 'void *' から 'Node *' に変換できません。	ConsoleAエラー	C2440	'初期化中': '
エラー	C2440	'初期化中': 'void *' から 'Tree *' に変換できません。	ConsoleAエラー	C2440	'初期化中': '
エラー	C2131	式は定数に評価されませんでした	ConsoleApplication2	c:\usersエラー	C2131	式は定数に評価
エラー	C2440	'=': 'void *' から 'int *' に変換できません。	ConsoleApplicatiエラー	C2440	'=': 'void *'
エラー	C2440	'=': 'void *' から 'int (*)[n]' に変換できません。	ConsoleAエラー	C2440	'=': 'void *'
エラー	C2440	'=': 'void *' から 'int *' に変換できません。	ConsoleApplicatiエラー	C2440	'=': 'void *'
エラー	C3863	配列型 'int [n]' を割り当てることはできません。	ConsoleApplicatiエラー	C3863	配列型 'int [
警告	C4996	'scanf': This function or variable may be unsafe. Consider using警告	C4996	'scanf': This
C++の仕様に基づくメッセージがあるようです。
code=Cと書かれているので、C++ではなくC言語としてコンパイルするべきでしょう。
オフトピック
あれ?
No: 5のコードでも同様にC++だとエラーになるvoid*からオブジェクトへのポインタへの暗黙の変換を使っているのに、
こっちは「コンパイルが通ります」と主張している。
妙だな。
まさか、事実をゆがめて中傷をしようとしている!?
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)

Math

Re: AVL木の実装で困っています

#10

投稿記事 by Math » 8年前

あ、すいません。また勘違いしていました。コマンドライン・コンパイルでは/TC で.cppでもCとしてコンパイルしてくれるのにIDEでは.cに戻すのを忘れてました。するとコンパイルはOKでしたか?

RIKU13

Re: AVL木の実装で困っています

#11

投稿記事 by RIKU13 » 8年前

お二人ともありがとうございます。
インデント等雑ですいません。
insert_node関数のどこを治すとうまくいくのでしょうか?いろいろ試してはいるのですがどうしても実行できないのでお願いします。

RIKU13

Re: AVL木の実装で困っています

#12

投稿記事 by RIKU13 » 8年前

このように大幅に変えてみたのですが、やはりうまくいきませんでした。
アドバイスお願いします。
static Node *insert_node(int element,Node *node)
{
Node *prev = NULL;

if (node == NULL)
node = make_node(element,prev);
else if (element < node->element){
prev = node->left = insert_node(element,node->left);
}
else if (element > node->element){
prev = node->right = insert_node(element,node->right);
}
if (prev != NULL)
rebalance(prev, element < prev->element ? AVL_LEFT : AVL_RIGHT);
return node;

}

Math

Re: AVL木の実装で困っています

#13

投稿記事 by Math » 8年前

インデントを直しビルド・エラーを送ります。231行目に心当たりはありませんか?

コード:

重大度レベル	コード	説明	プロジェクト	ファイル	行	抑制状態
----------------------------------------------------------------------------------
エラー	C2466	サイズが 0 の配列を割り当てまたは宣言しようとしました。	ConsAVLtree	d:\h\vs2015\001\consavltree\consavltree\c1.c	231	
エラー	C2057	定数式が必要です。	ConsAVLtree	d:\h\vs2015\001\consavltree\consavltree\c1.c	231	
エラー	C2036	'int (*)[0]':     サイズが不明です。	ConsAVLtree	d:\h\vs2015\001\consavltree\consavltree\c1.c	308	
エラー (アクティブ)式には定数値が必要です	ConsAVLtree	d:\h\vs2015\001\ConsAVLtree\ConsAVLtree\c1.c	231	

コード:

#define _CRT_SECURE_NO_WARNINGS
/*以下のようなAVL木のコードを書いてみたのですがセグメンテーション違反が出てしまい
原因が分からず困っています。
内容としては、ある数列をAVL木として挿入を行い、数列の数が50個までの場合は可視化
を行っています。初心者であるため、かなり煩雑なコードになっていますが、アドバイス
お願いいたします。なるべく早く返信を頂けると幸いです。
私の予想としてはinsert_nodeとrebalanceの中身でミスをしているのではないかという
検討を立てています。
*/
#include<stdio.h>
#include<stdlib.h>
#include<math.h>
#include<time.h>
#define VISION 50
#define AVL_BALANCED 0
#define AVL_LEFT 1
#define AVL_RIGHT 2

typedef struct node {
	struct node *left;
	struct node *right;
	struct node *parent;
	int element;
	int balance;
}Node;

typedef struct {
	Node *root;
}Tree;

static void destroy_node(Node *node)//-----------------------------------------
{
	if (node != NULL) {
		destroy_node(node->left);
		destroy_node(node->right);
		free(node);
	}
}

void rebalance(Node *node, int direct)//---------------------------------------
{
	Node *prev, *next;

	if (node == NULL) return;
	if ((node->balance == AVL_LEFT && direct == AVL_RIGHT)
		|| (node->balance == AVL_RIGHT && direct == AVL_LEFT))
	{
		node->balance = AVL_BALANCED;
	}
	else if (node->balance == AVL_BALANCED) {
		node->balance = direct;
		if ((prev = node->parent) != NULL)
			rebalance(prev, node->element < prev->element ? AVL_LEFT : AVL_RIGHT);
	}
	else if (node->balance == direct) {
		prev = node->parent;
		if (node->left->balance == direct) {
			next = (direct == AVL_LEFT) ? node->left : node->right;
			node->parent = next;
			next->parent = prev;
			if (direct == AVL_LEFT) {
				node->left = next->right;
				next->right = node;
			}
			else {
				node->right = next->left;
				next->left = node;
			}
			node->balance = AVL_BALANCED;
			next->balance = AVL_BALANCED;
		}
		else {
			Node *dene;
			if (direct == AVL_LEFT) {
				dene = node->left;
				next = dene->right;
			}
			else {
				dene = node->right;
				next = dene->left;
			}

			node->parent = next;
			dene->parent = next;
			next->parent = prev;
			if (direct == AVL_LEFT) {
				node->left = next->right;
				next->right = node;
				dene->right = next->left;
				next->left = dene;
				dene->balance = (next->balance == AVL_RIGHT) ?
					AVL_LEFT : AVL_BALANCED;
				node->balance = (next->balance == AVL_LEFT) ?
					AVL_RIGHT : AVL_BALANCED;
			}
			else {
				node->right = next->left;
				next->left = node;
				dene->left = next->right;
				next->right = dene;
				dene->balance = (next->balance == AVL_LEFT) ?
					AVL_RIGHT : AVL_BALANCED;
				node->balance = (next->balance == AVL_RIGHT) ?
					AVL_LEFT : AVL_BALANCED;
			}
			next->balance = AVL_BALANCED;
		}
		if (prev->parent == NULL)
			prev->left = prev->right = next;
		else if (node->element < prev->element) prev->left = next;
		else prev->right = next;
	}
}
static Node *make_node(int element, Node *prev)//------------------------------
{
	Node *node = malloc(sizeof(Node));
	if (node != NULL) {
		node->element = element;
		node->left = NULL;
		node->right = NULL;
		node->balance = 0;
		node->parent = prev;
	}
	return node;
}
/*
static Node *insert_node(int element, Node *node)//----------------------------
{
Node *prev = NULL;

while (node != NULL) {
if (element == node->element) return NULL;
prev = node;
if (element < node->element)
node->left = insert_node(element, node->left);
else
node->right = insert_node(element, node->right);
}
make_node(element, prev);
if (prev != NULL)
rebalance(prev, element < prev->element ? AVL_LEFT : AVL_RIGHT);
return node;

}
*/
static Node *insert_node(int element, Node *node)//----------------------------
{
	Node *prev = NULL;

	if (node == NULL)
		node = make_node(element, prev);
	else if (element < node->element) {
		prev = node->left = insert_node(element, node->left);
	}
	else if (element > node->element) {
		prev = node->right = insert_node(element, node->right);
	}
	if (prev != NULL)
		rebalance(prev, element < prev->element ? AVL_LEFT : AVL_RIGHT);
	return node;

}
int depth_node(int element, Node *node)//--------------------------------------
{
	int depth = 0;
	while (node->element != element) {
		if (element < node->element) {
			node = node->left;
		}
		else {
			node = node->right;
		}
		depth++;
	}
	return depth;
}

int depth_tree(int element, Tree *tree)//-------------------------------------
{
	return depth_node(element, tree->root);
}

Tree *make_tree(void)//--------------------------------------------------------
{
	Tree *tree = malloc(sizeof(Tree));
	if (tree != NULL) {
		tree->root = NULL;
	}
	return tree;
}

void insert_tree(int elememt, Tree *tree)//------------------------------------
{
	tree->root = insert_node(elememt, tree->root);
}

void destroy_tree(Tree *tree)//------------------------------------------------
{
	destroy_node(tree->root);
	free(tree);

}

int GetRandom(int min, int max)
{
	return min + (int)(rand()*(max - min + 1.0) / (1.0 + RAND_MAX));
}

void shuffle(int *num, int n)//------------------------------------------------
{
	int s, m, tmp;
	for (s = n - 1; s > 0; s--) {
		m = rand() % (s + 1);
		tmp = num[s];
		num[s] = num[m];
		num[m] = tmp;
	}
}
int main(void)/////////////////////////////////////////////////////////////////
{
	int i, n, x, y, z, tree_number, *num, (*vision)[VISION],
		depth, height, error, *height_tree;
	double sum_height = 0, sum2_height = 0, real_number = 0, average1, average2;

	srand((unsigned int)time(NULL));

	printf("!!");
	fflush(0);
	scanf("%d", &n);

	int(*check_tree)[n]; ////////////////////////////////////////////////////// 231 --- n

	tree_number = (int)((double)n / log2((double)n));
	num = calloc(n, sizeof(int));
	check_tree = calloc(tree_number * n, sizeof(int));
	height_tree = calloc(n, sizeof(int));

	for (i = 0; i < n; i++)
		num[i] = i + 1;
	for (x = 0; x < tree_number; x++) {
		Tree *tree = make_tree();
		if (n <= VISION)
			vision = calloc(VISION * VISION, sizeof(int));
		height = 0;
		error = 0;
		shuffle(num, n);
		for (i = 0; i < n; i++) {
			insert_tree(num[i], tree);
			if (n <= VISION)
				printf("%d ", num[i]);
		}
		for (i = 0; i < n; i++) {
			depth = depth_tree(num[i], tree);
			if (n <= VISION)
				vision[depth][num[i] - 1] = num[i];
			if (depth >= height)
				height = depth;
			check_tree[x][num[i] - 1] = depth;
		}

		for (y = 0; y < x; y++) {
			for (z = 0; z < n; z++) {
				if (check_tree[y][z] != check_tree[x][z])
					break;
			}
			if ((z == n) && (check_tree[y][z - 1] == check_tree[x][z - 1])) {
				error++;
				break;
			}
		}
		if (x != 0 && error == 1) {
			printf("this tree has been already created\n");
			if (n <= VISION)
				free(vision);
			destroy_tree(tree);
			continue;
		}
		if (n <= VISION) {
			printf("\n");
			for (y = 0; y <= height; y++) {
				for (z = 0; z < n; z++) {
					if (vision[y][z] != 0)
						printf("%2d", vision[y][z]);
					else
						printf(" ");
				}
				printf("\n");
			}
			printf("%d\n", height);
		}
		if (n <= VISION)
			free(vision);
		destroy_tree(tree);
		height_tree[height]++;
	}
	for (i = 0; i < n; i++) {
		sum_height += (i * height_tree[i]);
		sum2_height += (i * i * height_tree[i]);
		real_number += height_tree[i];
	}
	average1 = sum_height / tree_number;
	average2 = sum2_height / tree_number;

	printf("%f\n%f\n", average1, average2 - average1 * average1);
	free(check_tree);
	free(height_tree);
	return 0;
}
///EOF///

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

Re: AVL木の実装で困っています

#14

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

Math さんが書きました:インデントを直しビルド・エラーを送ります。231行目に心当たりはありませんか?

コード:

重大度レベル	コード	説明	プロジェクト	ファイル	行	抑制状態
----------------------------------------------------------------------------------
エラー	C2466	サイズが 0 の配列を割り当てまたは宣言しようとしました。	ConsAVLtree	d:\h\vs2015\001\consavltree\consavltree\c1.c	231	
エラー	C2057	定数式が必要です。	ConsAVLtree	d:\h\vs2015\001\consavltree\consavltree\c1.c	231	
エラー	C2036	'int (*)[0]':     サイズが不明です。	ConsAVLtree	d:\h\vs2015\001\consavltree\consavltree\c1.c	308	
エラー (アクティブ)式には定数値が必要です	ConsAVLtree	d:\h\vs2015\001\ConsAVLtree\ConsAVLtree\c1.c	231	
変数を要素数とする配列はC99から対応しています。
このエラーの原因は、コンパイラの性能が悪い、または前の規格に従うモードであるため対応していないことでしょう。
Math さんが書きました:するとコンパイルはOKでしたか?
「セグメンテーション違反が出てしまい」とあるので、実行できている、すなわちコンパイルはできていると読めるでしょう。
オフトピック
コンパイラの品質が悪く、コンパイラの方がセグメンテーション違反を出している可能性がないわけではありませんが…
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)

Math

Re: AVL木の実装で困っています

#15

投稿記事 by Math » 8年前

今回はVS2015Communityを使用してc1.cでビルド。最初からこの位置でVS2015のコードに波線が(nに)入って怪しかった。cにしてそのエラーだけになった。

metalg_taken
記事: 1
登録日時: 8年前

Re: AVL木の実装で困っています

#16

投稿記事 by metalg_taken » 8年前

コード:

#include<stdio.h>
#include<stdlib.h>
#include<math.h>
#include<time.h>
#define VISION 50
#define AVL_BALANCED 0
#define AVL_LEFT 1
#define AVL_RIGHT 2
 
typedef struct node {
    struct node *left;
    struct node *right;
    struct node *parent;
    int element;
    int balance;
}Node;
 
typedef struct {
    Node *root;
}Tree;
 
static void destroy_node(Node *node)
{
    if (node != NULL) {
        destroy_node(node->left);
        destroy_node(node->right);
        free(node);
    }
}
 
/*void rebalance(Node *node, int direct)
{
    Node *prev, *next;
 
    if (node == NULL) return;
    if ((node->balance == AVL_LEFT && direct == AVL_RIGHT)
        || (node->balance == AVL_RIGHT && direct == AVL_LEFT))
    {
        node->balance = AVL_BALANCED;
    }
    else if (node->balance == AVL_BALANCED) {
        node->balance = direct;
        if ((prev = node->parent) != NULL)
            rebalance(prev, node->element < prev->element ? AVL_LEFT : AVL_RIGHT);
    }
    else if (node->balance == direct) {
        prev = node->parent;
        if (node->left->balance == direct) {
            next = (direct == AVL_LEFT) ? node->left : node->right;
            node->parent = next;
            next->parent = prev;
            if (direct == AVL_LEFT) {
                node->left = next->right;
                next->right = node;
            }
            else {
                node->right = next->left;
                next->left = node;
            }
            node->balance = AVL_BALANCED;
            next->balance = AVL_BALANCED;
        }
        else {
            Node *dene;
            if (direct == AVL_LEFT) {
                dene = node->left;
                next = dene->right;
            }
            else {
                dene = node->right;
                next = dene->left;
            }
 
            node->parent = next;
            dene->parent = next;
            next->parent = prev;
            if (direct == AVL_LEFT) {
                node->left = next->right;
                next->right = node;
                dene->right = next->left;
                next->left = dene;
                dene->balance = (next->balance == AVL_RIGHT) ?
                    AVL_LEFT : AVL_BALANCED;
                node->balance = (next->balance == AVL_LEFT) ?
                    AVL_RIGHT : AVL_BALANCED;
            }
            else {
                node->right = next->left;
                next->left = node;
                dene->left = next->right;
                next->right = dene;
                dene->balance = (next->balance == AVL_LEFT) ?
                    AVL_RIGHT : AVL_BALANCED;
                node->balance = (next->balance == AVL_RIGHT) ?
                    AVL_LEFT : AVL_BALANCED;
            }
            next->balance = AVL_BALANCED;
        }
        if (prev->parent == NULL)
            prev->left = prev->right = next;
        else if (node->element < prev->element) prev->left = next;
        else prev->right = next;
    }
}
*/

static Node *make_node(int element, Node *prev)
{
    Node *node = malloc(sizeof(Node));
    if (node != NULL) {
        node->element = element;
        node->left = NULL;
        node->right = NULL;
        node->balance = 0;
        node->parent = prev;
    }
    return node;
}

static Node *insert_node(int element, Node *node)
{
    Node *prev = NULL;
 
    if (node == NULL)
        node = make_node(element, prev);
    else if (element < node->element) {
        prev = node->left = insert_node(element, node->left);
    }
    else if (element > node->element) {
        prev = node->right = insert_node(element, node->right);
    }
    if (prev != NULL)
        //rebalance(prev, element < prev->element ? AVL_LEFT : AVL_RIGHT);
    return node;
}

int depth_node(int element, Node *node)
{
    int depth = 0;
    while (node->element != element) {
        if (element < node->element) {
            node = node->left;
        }
        else {
            node = node->right;
        }
        depth++;
    }
    return depth;
}

int depth_tree(int element, Tree *tree)
{
    return depth_node(element, tree->root);
}
 
Tree *make_tree(void)
{
    Tree *tree = malloc(sizeof(Tree));
    if (tree != NULL) {
        tree->root = NULL;
    }
    return tree;
}
 
void insert_tree(int elememt, Tree *tree)
{
    tree->root = insert_node(elememt, tree->root);
}
 
void destroy_tree(Tree *tree)
{
    destroy_node(tree->root);
    free(tree);
 
}
 
int GetRandom(int min, int max)
{
    return min + (int)(rand()*(max - min + 1.0) / (1.0 + RAND_MAX));
}
 
void shuffle(int *num, int n)
{
    int s, m, tmp;
    for (s = n - 1; s > 0; s--) {
        m = rand() % (s + 1);
        tmp = num[s];
        num[s] = num[m];
        num[m] = tmp;
    }
}
int main(void)
{
    int i, n, x, y, z, tree_number, *num, **vision,
        depth, height, error, *height_tree, **check_tree;
    double sum_height = 0, sum2_height = 0, real_number = 0, average1, average2;
 
    srand((unsigned int)time(NULL));
 
    printf("Input n: ");
    fflush(0);
    scanf("%d", &n);
 
    tree_number = (int)((double)n / log2((double)n));
    num = calloc(n, sizeof(int));
	if ((check_tree = (int **)calloc(tree_number, sizeof(int *))) == NULL) {
		fprintf(stderr, "Error\n");
		exit(1);
	}
	for (i = 0; i < tree_number; i++) {
		if ((check_tree[i] = (int *)calloc(n, sizeof(int))) == NULL) {
			fprintf(stderr, "Error\n");
			exit(2);
		}
	}
    height_tree = calloc(n, sizeof(int));
 
    for (i = 0; i < n; i++)
        num[i] = i + 1;
    for (x = 0; x < tree_number; x++) {
        Tree *tree = make_tree();
        if (n <= VISION) {
			if ((vision = (int **)
				 calloc(VISION, sizeof(int *))) == NULL) {
				fprintf(stderr, "Error\n");
				exit(1);
			}
			for (i = 0; i < VISION; i++) {
				if ((vision[i] = (int *)calloc(VISION, sizeof(int))) == NULL) {
					fprintf(stderr, "Error\n");
					exit(2);
				}
			}
		}
		height = 0;
        error = 0;
        shuffle(num, n);
        for (i = 0; i < n; i++) {
            insert_tree(num[i], tree);
            if (n <= VISION)
                printf("%d ", num[i]);
        }
        for (i = 0; i < n; i++) {
            depth = depth_tree(num[i], tree);
            if (n <= VISION)
                vision[depth][num[i] - 1] = num[i];
            if (depth >= height)
                height = depth;
            check_tree[x][num[i] - 1] = depth;
        }
 
        for (y = 0; y < x; y++) {
            for (z = 0; z < n; z++) {
                if (check_tree[y][z] != check_tree[x][z])
                    break;
            }
            if ((z == n) && (check_tree[y][z - 1] == check_tree[x][z - 1])) {
                error++;
                break;
            }
        }
        if (x != 0 && error == 1) {
            printf("this tree has been already created\n");
            if (n <= VISION)
                free(vision);
            destroy_tree(tree);
            continue;
        }
        if (n <= VISION) {
            printf("\n");
            for (y = 0; y <= height; y++) {
                for (z = 0; z < n; z++) {
                    if (vision[y][z] != 0)
                        printf("%2d", vision[y][z]);
                    else
                        printf("%2s", " ");
                }
                printf("\n");
            }
            printf("height = %d\n\n", height);
        }
        if (n <= VISION)
            free(vision);
        destroy_tree(tree);
        height_tree[height]++;
    }
    for (i = 0; i < n; i++) {
        sum_height += (i * height_tree[i]);
        sum2_height += (i * i * height_tree[i]);
        real_number += height_tree[i];
    }
    average1 = sum_height / tree_number;
    average2 = sum2_height / tree_number;
 
    printf("%f\n%f\n", average1, average2 - average1 * average1);
    free(check_tree);
    free(height_tree);
    return 0;
}
訂正した部分とアドバイスをいくつか・・・
1.木の表示の部分で%2dとしているのならば、見栄えをよくするために空白も2文字分入れるとよいと思います。
2.callocを2回用いることによって、2次元配列の領域を確保してみました。領域確保に関してはこれで大丈夫だと思います。
 それと、領域確保できなかったときのエラーメッセージを入れておいた方が良いと思います。

このようにすると普通の木はちゃんと作れたので、おそらくrebalance関数内に問題があるのかと思われます。

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

Re: AVL木の実装で困っています

#17

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

metalg_taken さんが書きました:このようにすると普通の木はちゃんと作れたので
それはたまたまでしょう。
insert_node関数において、引数nodeがNULLのとき、return文を通らずに関数が終了するので返される値は不定になり、その返り値を用いると未定義動作になります。
Wandboxで実験をしたところ、
最適化をかけない場合はたまたまうまく動いてしまいましたが、
最適化をかけるとSegnemtation Faultになりました
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)

RIKU13
記事: 2
登録日時: 8年前

Re: AVL木の実装で困っています

#18

投稿記事 by RIKU13 » 8年前

みなさんありがとうございます。
みなさんのアドバイスを元にいろいろ試してみてはいるのですが、いまだ動作していません。
rebalance,もしくはinsertが異常を示しているのは確かとは思います。その手の改善点があればお願いします。

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

Re: AVL木の実装で困っています

#19

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

闇雲にコードを書き換えて実行してみるだけでなく、デバッガやprintfデバッグなどによる解析はしていますか?
最新のコードがないと、こちらでデバッグをするのは難しいと思います。
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)

RIKU13
記事: 2
登録日時: 8年前

Re: AVL木の実装で困っています

#20

投稿記事 by RIKU13 » 8年前

特にソースは変更する前の状態に戻しました。やはりrebalanceがおかしいのでしょうか。eclipseを使用していますが10を入力すると動作が停止してしまうためprintfデバックが使えません。

Math

Re: AVL木の実装で困っています

#21

投稿記事 by Math » 8年前

(あ、私の双方向listのProgramは書き方が参考にならないのですね)

コード:

	Node *node = (Node *)malloc(sizeof(Node));//<<<-----(Node *)---------------

コード:

	Tree *tree = (Tree *)malloc(sizeof(Tree));//<<<----------------------------

コード:

        num =(int *) calloc(n, sizeof(int));//<<<-------------------------------------

コード:

	height_tree =(int *)calloc(n, sizeof(int));//<<<---------------------------------
の4か所訂正で直ると思います。

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

Re: AVL木の実装で困っています

#22

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

C言語においては、malloc()系のメモリ確保関数の戻り値は自動で変換されるので、明示的にはキャストしないべきであるという主張があります。
c - Do I cast the result of malloc? - Stack Overflow
Math さんが書きました:

コード:

	Node *node = (Node *)malloc(sizeof(Node));//<<<-----(Node *)---------------

コード:

	Tree *tree = (Tree *)malloc(sizeof(Tree));//<<<----------------------------

コード:

        num =(int *) calloc(n, sizeof(int));//<<<-------------------------------------

コード:

	height_tree =(int *)calloc(n, sizeof(int));//<<<---------------------------------
の4か所訂正で直ると思います。
どうしてそう思うのですか?
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)

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

Re: AVL木の実装で困っています

#23

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

RIKU13 さんが書きました:特にソースは変更する前の状態に戻しました。
「変更する前」とは、具体的にどういう状態ですか?
確実に強制終了するコードに戻したら、確実に強制終了するのは当たり前でしょう。
RIKU13 さんが書きました:やはりrebalanceがおかしいのでしょうか。
そう思うなら、まずrebalanceの処理を無くしてみてそれでも落ちるかをチェックすることで、本当におかしそうかをチェックしましょう。
RIKU13 さんが書きました:printfデバックが使えません。
GDBなどのデバッガは使えますか?
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)

Math

Re: AVL木の実装で困っています

#24

投稿記事 by Math » 8年前

動作確認しました。[実行結果]Windows10,VC++2015Community(コマンドライン・コンパイル)

コード:

D:\h\z10\01\19\02>cl /EHsc c1.cpp
Microsoft(R) C/C++ Optimizing Compiler Version 19.00.24215.1 for x86
Copyright (C) Microsoft Corporation.  All rights reserved.

c1.cpp
d:\h\z10\01\19\02\c1.cpp(136) : warning C4715: 'insert_node': 値を返さないコントロール パスがあります。
Microsoft (R) Incremental Linker Version 14.00.24215.1
Copyright (C) Microsoft Corporation.  All rights reserved.

/out:c1.exe
c1.obj

D:\h\z10\01\19\02>rem -------------------------------- c1.exe

D:\h\z10\01\19\02>c1.exe
Start--->
Input n: 10
001:shuffle:24 2 6 8 1 7 5 10 9 3
       4
   2       6
 1   3   5     8
             7    10
                 9
height = 4

001:shuffle:87 8 1 10 6 3 4 2 5 9
             7
 1             8
           6      10
     3           9
   2   4
         5
height = 5

001:shuffle:88 5 2 3 9 10 1 6 4 7
               8
         5       9
   2       6      10
 1   3       7
       4
height = 4

4.333333
0.222222

D:\h\z10\01\19\02>
[c.bat]コマンドライン・コンパイル用バッチファイル

コード:

cl /EHsc c1.cpp
rem -------------------------------- c1.exe
c1.exe

Math

Re: AVL木の実装で困っています

#25

投稿記事 by Math » 8年前

[c1.cpp]

コード:

#define _CRT_SECURE_NO_WARNING
#include<stdio.h>/////////////
#include<stdlib.h>////////////
#include<math.h>//////////////
#include<time.h>//////////////           AVL Tree
#define VISION 50/////////////
#define AVL_BALANCED 0////////
#define AVL_LEFT 1    ////////
#define AVL_RIGHT 2   ////////
                      ////////
typedef struct node {//Tree構造体
	struct node *left;//////左///
	struct node *right;////右////
	struct node *parent;//親/////
	int element;//メンバ[element]
	int balance;//メンバ[balance]
}Node;//Node型///////////////////
                               //  
typedef struct {//Nodeのポインター//
	Node *root;                  //
}Tree;//Tree型////////////////////

static void destroy_node(Node *node)
{
	if (node != NULL) {
		destroy_node(node->left);
		destroy_node(node->right);
		free(node);
	}
}

/*void rebalance(Node *node, int direct)
{
Node *prev, *next;

if (node == NULL) return;
if ((node->balance == AVL_LEFT && direct == AVL_RIGHT)
|| (node->balance == AVL_RIGHT && direct == AVL_LEFT))
{
node->balance = AVL_BALANCED;
}
else if (node->balance == AVL_BALANCED) {
node->balance = direct;
if ((prev = node->parent) != NULL)
rebalance(prev, node->element < prev->element ? AVL_LEFT : AVL_RIGHT);
}
else if (node->balance == direct) {
prev = node->parent;
if (node->left->balance == direct) {
next = (direct == AVL_LEFT) ? node->left : node->right;
node->parent = next;
next->parent = prev;
if (direct == AVL_LEFT) {
node->left = next->right;
next->right = node;
}
else {
node->right = next->left;
next->left = node;
}
node->balance = AVL_BALANCED;
next->balance = AVL_BALANCED;
}
else {
Node *dene;
if (direct == AVL_LEFT) {
dene = node->left;
next = dene->right;
}
else {
dene = node->right;
next = dene->left;
}

node->parent = next;
dene->parent = next;
next->parent = prev;
if (direct == AVL_LEFT) {
node->left = next->right;
next->right = node;
dene->right = next->left;
next->left = dene;
dene->balance = (next->balance == AVL_RIGHT) ?
AVL_LEFT : AVL_BALANCED;
node->balance = (next->balance == AVL_LEFT) ?
AVL_RIGHT : AVL_BALANCED;
}
else {
node->right = next->left;
next->left = node;
dene->left = next->right;
next->right = dene;
dene->balance = (next->balance == AVL_LEFT) ?
AVL_RIGHT : AVL_BALANCED;
node->balance = (next->balance == AVL_RIGHT) ?
AVL_LEFT : AVL_BALANCED;
}
next->balance = AVL_BALANCED;
}
if (prev->parent == NULL)
prev->left = prev->right = next;
else if (node->element < prev->element) prev->left = next;
else prev->right = next;
}
}
*/

static Node *make_node(int element, Node *prev)
{
	Node *node = (Node *)malloc(sizeof(Node));//<<<-----(Node *)---------------
	if (node != NULL) {
		node->element = element;
		node->left = NULL;
		node->right = NULL;
		node->balance = 0;
		node->parent = prev;
	}
	return node;
}

static Node *insert_node(int element, Node *node)
{
	Node *prev = NULL;

	if (node == NULL)
		node = make_node(element, prev);
	else if (element < node->element) {
		prev = node->left = insert_node(element, node->left);
	}
	else if (element > node->element) {
		prev = node->right = insert_node(element, node->right);
	}
	if (prev != NULL)
		//rebalance(prev, element < prev->element ? AVL_LEFT : AVL_RIGHT);
		return node;
}

int depth_node(int element, Node *node)
{
	int depth = 0;
	while (node->element != element) {
		if (element < node->element) {
			node = node->left;
		}
		else {
			node = node->right;
		}
		depth++;
	}
	return depth;
}

int depth_tree(int element, Tree *tree)
{
	return depth_node(element, tree->root);
}

Tree *make_tree(void)
{
	Tree *tree = (Tree *)malloc(sizeof(Tree));//<<<----------------------------
	if (tree != NULL) {
		tree->root = NULL;
	}
	return tree;
}

void insert_tree(int elememt, Tree *tree)
{
	tree->root = insert_node(elememt, tree->root);
}

void destroy_tree(Tree *tree)
{
	destroy_node(tree->root);
	free(tree);

}

int GetRandom(int min, int max)
{
	return min + (int)(rand()*(max - min + 1.0) / (1.0 + RAND_MAX));
}

void shuffle(int *num, int n)
{
	int s, m, tmp;
	for (s = n - 1; s > 0; s--) {
		m = rand() % (s + 1);
		tmp = num[s];
		num[s] = num[m];
		num[m] = tmp;
	}printf("001:shuffle:%d", tmp);//------------------------------------------
}
int main(void)/////////////////////////////////////////////////////////////////①
{
	int i, n, x, y, z, tree_number, *num, **vision,
		depth, height, error, *height_tree, **check_tree;
	double sum_height = 0, sum2_height = 0, real_number = 0, average1, average2;

	srand((unsigned int)time(NULL));//乱数発生装置
	printf("Start--->\n");
	printf("Input n: ");//n入力
	fflush(0);
	scanf("%d", &n);

	tree_number = (int)((double)n / log2((double)n));
	num =(int *) calloc(n, sizeof(int));//<<<-------------------------------------
	if ((check_tree = (int **)calloc(tree_number, sizeof(int *))) == NULL) {
		fprintf(stderr, "Error\n");
		exit(1);
	}
	for (i = 0; i < tree_number; i++) {
		if ((check_tree[i] = (int *)calloc(n, sizeof(int))) == NULL) {
			fprintf(stderr, "Error\n");
			exit(2);
		}
	}
	height_tree =(int *)calloc(n, sizeof(int));//<<<---------------------------------

	for (i = 0; i < n; i++)
		num[i] = i + 1;
	for (x = 0; x < tree_number; x++) {
		Tree *tree = make_tree();
		if (n <= VISION) {
			if ((vision = (int **)
				calloc(VISION, sizeof(int *))) == NULL) {
				fprintf(stderr, "Error\n");
				exit(1);
			}
			for (i = 0; i < VISION; i++) {
				if ((vision[i] = (int *)calloc(VISION, sizeof(int))) == NULL) {
					fprintf(stderr, "Error\n");
					exit(2);
				}
			}
		}
		height = 0;
		error = 0;
		shuffle(num, n);
		for (i = 0; i < n; i++) {
			insert_tree(num[i], tree);
			if (n <= VISION)
				printf("%d ", num[i]);
		}
		for (i = 0; i < n; i++) {
			depth = depth_tree(num[i], tree);
			if (n <= VISION)
				vision[depth][num[i] - 1] = num[i];
			if (depth >= height)
				height = depth;
			check_tree[x][num[i] - 1] = depth;
		}

		for (y = 0; y < x; y++) {
			for (z = 0; z < n; z++) {
				if (check_tree[y][z] != check_tree[x][z])
					break;
			}
			if ((z == n) && (check_tree[y][z - 1] == check_tree[x][z - 1])) {
				error++;
				break;
			}
		}
		if (x != 0 && error == 1) {
			printf("this tree has been already created\n");
			if (n <= VISION)
				free(vision);
			destroy_tree(tree);
			continue;
		}
		if (n <= VISION) {
			printf("\n");
			for (y = 0; y <= height; y++) {
				for (z = 0; z < n; z++) {
					if (vision[y][z] != 0)
						printf("%2d", vision[y][z]);
					else
						printf("%2s", " ");
				}
				printf("\n");
			}
			printf("height = %d\n\n", height);
		}
		if (n <= VISION)
			free(vision);
		destroy_tree(tree);
		height_tree[height]++;
	}
	for (i = 0; i < n; i++) {
		sum_height += (i * height_tree[i]);
		sum2_height += (i * i * height_tree[i]);
		real_number += height_tree[i];
	}
	average1 = sum_height / tree_number;
	average2 = sum2_height / tree_number;

	printf("%f\n%f\n", average1, average2 - average1 * average1);
	free(check_tree);
	free(height_tree);
	return 0;
}

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

Re: AVL木の実装で困っています

#26

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

Math さんが書きました:動作確認しました。
このコードは、insert_node関数に引数node=NULLを渡した時return文を通らずに戻るので戻り値が不定になり、
その不定の戻り値をtree->rootに代入して次回のinsert_node関数の呼び出しで使うので、未定義動作です。
No: 16のmetalg_takenさんのコードと同じバグです。
たまたま上手く動いているように見えてしまったのは、運が悪かったですね。

代入後のtree->rootの値を出力する処理を追加した所、
最適化をかけない場合はたまたまいい感じの値になってたまたまうまく動くように見えてしまうが、
最適化をかけるとたまたま変な値になってたまたまSegmentation Faultになるという現象が観測できました。
Math さんが書きました:

コード:

d:\h\z10\01\19\02\c1.cpp(136) : warning C4715: 'insert_node': 値を返さないコントロール パスがあります。
ちゃんと警告が出ていますね。無視してはいけません。
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)

Math

Re: AVL木の実装で困っています

#27

投稿記事 by Math » 8年前

なるほど。そういう警告だったのですか。(気にはなったけど..)
[雑談]javaFXはパラダイムシフトでswingとは(C#の)FormとWPFほど違っている。javaはswingを捨ててjavaFXにするらしい。mainがなくても動いたり..いままでと文法が違うらしい。とても分かりにくい...もう集中しないととても..

Math

Re: AVL木の実装で困っています

#28

投稿記事 by Math » 8年前

まあ何度やっても正常に動作するので"printf”Debugなり通常のDebugが可能なのでそうすれば解決するでしょう。

(しかしeclipsでC/C++言語を何回かトライしたがVS2015に比べ難解で相当習熟しないとVS2015のようにいかないので”printf--Debugが有効でしょうね。(まあVS2015でも有効ですが))

閉鎖

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