/*
* Copyright (c) 2007 Vojtech Mencl
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* - The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <test.h>
#include <print.h>
#include <adt/extavlrel.h>
#include <debug.h>
#include <panic.h>
#define NODE_COUNT 100
/*
* wrapper structure with a pointer to extended avl tree root
*/
static extavlreltree_t extreltree;
/*
* extavltree nodes in array for faster allocating
*/
static extavlreltree_node_t extavlreltree_nodes[NODE_COUNT];
/*
* head of free nodes' list:
*/
static extavlreltree_node_t *first_free_node = NULL;
static int extreltree_test_height(extavlreltree_node_t *node,bool timeout);
static extavlreltree_node_t *extreltree_test_parents(extavlreltree_node_t *node);
static void print_extreltree_structure_flat (extavlreltree_node_t *node, int level);
static bool extreltree_test_link(extavlreltree_t *tree, int node_count);
static void print_extreltree_link(extavlreltree_t *tree);
static extavlreltree_node_t *alloc_extavlreltree_node(void);
//vraci hloubku stromu
static int extreltree_test_height(extavlreltree_node_t *node,bool timeout)
{
int h1, h2;
if (!node) return -1;
h1 = extreltree_test_height(node->lft,timeout) + 1;
if (!timeout && node->lft_height != h1) {
printf("Bad height: %d of LEFT subtree in node: %d with address: %p\n",h1
,node
->key
,node
);
}
h2 = extreltree_test_height(node->rgt,0) + 1;
if (node->rgt_height != h2) {
printf("Bad height: %d of RIGHT subtree in node: %d with address: %p\n",h2
,node
->key
,node
);
}
if (!timeout && (((h1-h2)>0?h1-h2:h2-h1) > 1)) {
printf("Bad height: error in definition of avltree: %d with address: %p\n",node
->key
,node
);
}
return (node->lft_height > node->rgt_height? node->lft_height: node->rgt_height);
}
/** Tests par atribute of every tree node
*
*/
static extavlreltree_node_t *extreltree_test_parents(extavlreltree_node_t *node)
{
extavlreltree_node_t *tmp;
if (!node) return NULL;
if (node->lft) {
tmp = extreltree_test_parents(node->lft);
if (tmp != node) {
printf("Bad parent pointer at node with key: %d, address: %p\n",tmp
->key
,node
->lft
);
}
}
if (node->rgt) {
tmp = extreltree_test_parents(node->rgt);
if (tmp != node) {
printf("Bad parent pointer at node with key: %d, address: %p\n",tmp
->key
,node
->rgt
);
}
}
return node->par;
}
/** Checks list of nodes
*
*/
static bool extreltree_test_link(extavlreltree_t *tree, int node_count)
{
extavlreltree_node_t *node;
int i;
bool test_link = true;
for (i = 0,node = tree->head.next; node != &(tree->head); i++,node = node->next)
;
if (i != node_count) {
printf("\nBad node count!!! Counted: %d, right number: %d", i
, node_count
);
test_link = false;
}
for (i = 0,node = tree->head.prev; node != &(tree->head); i++,node = node->prev)
;
if (i != node_count) {
printf("\nBad node count!!! Counted: %d, right number: %d", i
, node_count
);
test_link = false;
}
return test_link;
}
static int _sum_extreltree(extavlreltree_node_t *node)
{
int sum = 0;
if (node->rgt)
sum += _sum_extreltree(node->rgt);
if (node->lft)
sum += _sum_extreltree(node->lft);
return sum + node->key;
}
static int extreltree_test_rgtsum(extavlreltree_node_t *node)
{
int rs, ls;
if (!node) return 0;
rs = extreltree_test_rgtsum(node->rgt);
ls = extreltree_test_rgtsum(node->lft);
if (rs != node->rgt_sum) {
printf("\nBad RGT_SUM: %d, should be: %d node: %d, address: %p\n",node
->rgt_sum
,rs
,node
->key
,node
);
}
return rs + ls + node->key;
}
/** Prints the structure of node, which is level levels from the top of the tree.
*
*/
static void print_extreltree_structure_flat (extavlreltree_node_t *node, int level)
{
extavlreltree_node_t *tmp;
int i;
if (level > 16)
{
return;
}
if (node == NULL)
return;
for (tmp = node->next,i = 0; (tmp->key == 0) && (tmp != &(extreltree.head)); tmp = tmp->next,i++)
;
printf ("%d[%d,%d]", node
->key
,node
->rgt_sum
,i
);
if (node->lft != NULL || node->rgt != NULL)
{
print_extreltree_structure_flat (node->lft, level + 1);
if (node->rgt != NULL)
{
print_extreltree_structure_flat (node->rgt, level + 1);
}
}
}
/** Prints list of nodes
*
*/
static void print_extreltree_link(extavlreltree_t *tree)
{
extavlreltree_node_t *node;
for (node = tree->head.next; node != &(tree->head); node = node->next) {
}
for (node = tree->head.prev; node != &(tree->head); node = node->prev) {
}
}
//****************************************************************
static void alloc_extavlreltree_node_prepare(void)
{
int i;
for (i = 0; i < NODE_COUNT - 1; i++) {
extavlreltree_nodes[i].next = &(extavlreltree_nodes[i+1]);
}
/*
* Node keys which will be used for insertion. Up to NODE_COUNT size of array.
*/
// First tree node and same key
extavlreltree_nodes[0].key = 60;
extavlreltree_nodes[1].key = 60;
extavlreltree_nodes[2].key = 60;
//LL rotation
extavlreltree_nodes[3].key = 50;
extavlreltree_nodes[4].key = 40;
extavlreltree_nodes[5].key = 30;
//LR rotation
extavlreltree_nodes[6].key = 20;
extavlreltree_nodes[7].key = 20;
extavlreltree_nodes[8].key = 25;
extavlreltree_nodes[9].key = 25;
//LL rotation in lower floor
extavlreltree_nodes[10].key = 35;
//RR rotation
extavlreltree_nodes[11].key = 70;
extavlreltree_nodes[12].key = 80;
//RL rotation
extavlreltree_nodes[13].key = 90;
extavlreltree_nodes[14].key = 85;
extavlreltree_nodes[15].key = 100;
extavlreltree_nodes[16].key = 200;
extavlreltree_nodes[17].key = 300;
extavlreltree_nodes[18].key = 400;
extavlreltree_nodes[19].key = 500;
extavlreltree_nodes[20].key = 600;
for (i = 21; i < NODE_COUNT; i++)
extavlreltree_nodes[i].key = i * 3;
extavlreltree_nodes[i].next = NULL;
first_free_node = &(extavlreltree_nodes[0]);
}
static extavlreltree_node_t *alloc_extavlreltree_node(void)
{
extavlreltree_node_t *node;
node = first_free_node;
first_free_node = first_free_node->next;
return node;
}
//****************************************************************
static void test_extreltree_insert(extavlreltree_t *tree, unsigned int node_count, int quiet)
{
unsigned int i;
extavlreltree_node_t *newnode;
/*
* Initialize tree before using.
*/
extavlreltree_create(tree);
if (!quiet
) printf("\nInserting %d nodes ...\n", node_count
);
for (i = 0; i < node_count; i++) {
newnode = alloc_extavlreltree_node();
//if (!quiet) printf("[[[%d]]]\n",newnode->key);
extavlreltree_insert(tree, newnode);
if (!quiet) {
if (!extreltree_test_link(tree,i+1)) {
print_extreltree_link(tree);
}
extreltree_test_parents(tree->root);
extreltree_test_height(tree->root,1);
extreltree_test_rgtsum(tree->root);
}
}
if (!quiet
) printf("Inserting was finished\n");
}
static void test_extreltree_delete(extavlreltree_t *tree, int node_count, int node_position, bool quiet)
{
extavlreltree_node_t *delnode;
unsigned int i;
//aktualni pocet tiku:
if (!quiet
) printf("Deleting tree...\n");
switch(node_position) {
case 0: //mazani vzdy korene
if (!quiet
) printf("\nDelete root nodes\n");
i = node_count - 1;
while(tree->root != NULL) {
delnode = tree->root;
extavlreltree_delete(tree,delnode);
if (!quiet) {
if (!extreltree_test_link(tree,i)) {
print_extreltree_link(tree);
}
extreltree_test_parents(tree->root);
extreltree_test_height(tree->root,1);
extreltree_test_rgtsum(tree->root);
}
i--;
}
break;
case 1:
if (!quiet
) printf("\nDelete nodes according to their time of origin\n");
for (i = 0; i < node_count; i++) {
extavlreltree_delete(tree,&(extavlreltree_nodes[i]));
if (!quiet) {
if (!extreltree_test_link(tree,node_count-i-1)) {
print_extreltree_link(tree);
}
extreltree_test_parents(tree->root);
extreltree_test_height(tree->root,1);
extreltree_test_rgtsum(tree->root);
}
}
break;
}
if (!quiet
) printf("Deletion was finished\n");
}
static void timeout_extreltree(extavlreltree_t *tree, int node_count, bool quiet)
{
int i = node_count - 1;
if (!quiet
) printf("\nTimeout tree ...\n");
while(tree->head.next != &(tree->head)) {
extavlreltree_delete_min(tree);
if (!quiet) {
if (!extreltree_test_link(tree,i)) {
print_extreltree_link(tree);
}
extreltree_test_parents(tree->root);
extreltree_test_height(tree->root,1);
extreltree_test_rgtsum(tree->root);
}
i--;
}
if (!quiet
&& (i
!= -1)) printf("Bad node count. Some nodes have been lost!\n");
if (!quiet
) printf("Timeout tree finished\n");
}
char * test_extavlreltree1(bool quiet)
{
alloc_extavlreltree_node_prepare();
test_extreltree_insert(&extreltree, NODE_COUNT, quiet);
test_extreltree_delete(&extreltree, NODE_COUNT, 0, quiet);
alloc_extavlreltree_node_prepare();
test_extreltree_insert(&extreltree, NODE_COUNT, quiet);
test_extreltree_delete(&extreltree, NODE_COUNT, 1, quiet);
alloc_extavlreltree_node_prepare();
test_extreltree_insert(&extreltree, NODE_COUNT, quiet);
timeout_extreltree(&extreltree, NODE_COUNT, quiet);
return NULL;
}