1341 lines
37 KiB
C++
1341 lines
37 KiB
C++
// Copyright (C) 2003 Davis E. King (davis@dlib.net)
|
|
// License: Boost Software License See LICENSE.txt for the full license.
|
|
#ifndef DLIB_SEQUENCE_KERNEl_1_
|
|
#define DLIB_SEQUENCE_KERNEl_1_
|
|
|
|
#include "sequence_kernel_abstract.h"
|
|
#include "../algs.h"
|
|
#include "../interfaces/enumerable.h"
|
|
#include "../interfaces/remover.h"
|
|
#include "../serialize.h"
|
|
|
|
namespace dlib
|
|
{
|
|
|
|
template <
|
|
typename T,
|
|
typename mem_manager = default_memory_manager
|
|
>
|
|
class sequence_kernel_1 : public enumerable<T>,
|
|
public remover<T>
|
|
{
|
|
|
|
/*!
|
|
INITIAL VALUE
|
|
- tree_root == 0
|
|
- tree_size == 0
|
|
- at_start_ == true
|
|
- current_element == 0
|
|
- stack == array of 50 node pointers
|
|
- stack_pos == 0
|
|
|
|
CONVENTION
|
|
|
|
- if (tree_size > 0)
|
|
- tree_root == pointer to the root node of the binary search tree
|
|
- else
|
|
- tree_root == 0
|
|
|
|
|
|
|
|
- stack[stack_pos-1] == pop()
|
|
|
|
- current_element_valid() == (current_element != 0)
|
|
|
|
- at_start_ == at_start()
|
|
- if (current_element != 0 && current_element != tree_root) then
|
|
- stack[stack_pos-1] == the parent of the node pointed to by current_element
|
|
|
|
- if (current_element_valid()) then
|
|
- element() == current_element->item
|
|
|
|
|
|
|
|
- tree_size == size()
|
|
- (*this)[i] == return_reference(i)
|
|
|
|
|
|
- for all nodes:
|
|
- left_size == the number of elements in the left subtree.
|
|
- left points to the left subtree or 0 if there is no left subtree.
|
|
- right points to the right subtree or 0 if there is no right subtree.
|
|
|
|
- all elements in a left subtree have a position in the sequence < that
|
|
of the root of the current tree.
|
|
|
|
- all elements in a right subtree have a position in the
|
|
sequence > that of the root of the current tree.
|
|
|
|
- item is the sequence element for that node.
|
|
- balance:
|
|
- balance == 0 if both subtrees have the same height
|
|
- balance == -1 if the left subtree has a height that is
|
|
greater than the height of the right subtree by 1
|
|
- balance == 1 if the right subtree has a height that is
|
|
greater than the height of the left subtree by 1
|
|
- for all subtrees:
|
|
- the height of the left and right subtrees differ by at most one
|
|
|
|
!*/
|
|
|
|
|
|
class node
|
|
{
|
|
public:
|
|
node* left;
|
|
node* right;
|
|
unsigned long left_size;
|
|
T item;
|
|
signed char balance;
|
|
};
|
|
|
|
|
|
|
|
public:
|
|
|
|
typedef T type;
|
|
typedef mem_manager mem_manager_type;
|
|
|
|
sequence_kernel_1 (
|
|
) :
|
|
tree_root(0),
|
|
tree_size(0),
|
|
stack(ppool.allocate_array(50)),
|
|
current_element(0),
|
|
at_start_(true),
|
|
stack_pos(0)
|
|
{}
|
|
|
|
virtual ~sequence_kernel_1 (
|
|
);
|
|
|
|
inline void clear (
|
|
);
|
|
|
|
void add (
|
|
unsigned long pos,
|
|
T& item
|
|
);
|
|
|
|
void remove (
|
|
unsigned long pos,
|
|
T& item
|
|
);
|
|
|
|
void cat (
|
|
sequence_kernel_1& item
|
|
);
|
|
|
|
const T& operator[] (
|
|
unsigned long pos
|
|
) const;
|
|
|
|
T& operator[] (
|
|
unsigned long pos
|
|
);
|
|
|
|
inline void swap (
|
|
sequence_kernel_1& item
|
|
);
|
|
|
|
// functions from the remover interface
|
|
inline void remove_any (
|
|
T& item
|
|
);
|
|
|
|
// functions from the enumerable interface
|
|
inline size_t size (
|
|
) const;
|
|
|
|
bool at_start (
|
|
) const;
|
|
|
|
inline void reset (
|
|
) const;
|
|
|
|
bool current_element_valid (
|
|
) const;
|
|
|
|
const T& element (
|
|
) const;
|
|
|
|
T& element (
|
|
);
|
|
|
|
bool move_next (
|
|
) const;
|
|
|
|
|
|
private:
|
|
|
|
void delete_nodes (
|
|
node* t
|
|
);
|
|
/*!
|
|
requires
|
|
- t == a pointer to a valid node
|
|
ensures
|
|
- deletes t and all its sub nodes.
|
|
!*/
|
|
|
|
inline void rotate_left (
|
|
node*& t
|
|
);
|
|
/*!
|
|
requires
|
|
- t->balance == 2
|
|
- t->right->balance == 0 or 1
|
|
ensures
|
|
- #t is still a binary search tree
|
|
- #t->balance is between 1 and -1
|
|
- #t now has a height smaller by 1 if #t->balance == 0
|
|
!*/
|
|
|
|
inline void rotate_right (
|
|
node*& t
|
|
);
|
|
/*!
|
|
requires
|
|
- t->balance == -2
|
|
- t->left->balance == 0 or -1
|
|
ensures
|
|
- #t is still a binary search tree
|
|
- #t->balance is between 1 and -1
|
|
- #t now has a height smaller by 1 if #t->balance == 0
|
|
|
|
!*/
|
|
|
|
inline void double_rotate_right (
|
|
node*& t
|
|
);
|
|
/*!
|
|
requires
|
|
- #t->balance == -2
|
|
- #t->left->balance == 1
|
|
ensures
|
|
- #t is still a binary search tree
|
|
- #t now has a balance of 0
|
|
- #t now has a height smaller by 1
|
|
!*/
|
|
|
|
inline void double_rotate_left (
|
|
node*& t
|
|
);
|
|
/*!
|
|
requires
|
|
- #t->balance == 2
|
|
- #t->right->balance == -1
|
|
ensures
|
|
- #t is still a binary search tree
|
|
- #t now has a balance of 0 and
|
|
- #t now has a height smaller by 1
|
|
!*/
|
|
|
|
bool remove_least_element_in_tree (
|
|
node*& t,
|
|
T& item
|
|
);
|
|
/*!
|
|
requires
|
|
- t != 0 (i.e. there must be something in the tree to remove)
|
|
ensures
|
|
- the least node in t has been removed
|
|
- the least node element in t has been put into #item
|
|
- #t is still a binary search tree
|
|
- returns false if the height of the tree has not changed
|
|
- returns true if the height of the tree has shrunk by one
|
|
!*/
|
|
|
|
bool add_to_tree (
|
|
node*& t,
|
|
unsigned long pos,
|
|
T& item
|
|
);
|
|
/*!
|
|
requires
|
|
- pos <= the number of items in the tree
|
|
ensures
|
|
- item has been added to #t
|
|
- #return_reference(pos) == item
|
|
- the convention is still satisfied
|
|
- #item has an initial value for its type
|
|
- returns false if the height of the tree has not changed
|
|
- returns true if the height of the tree has grown by one
|
|
!*/
|
|
|
|
bool remove_from_tree (
|
|
node*& t,
|
|
unsigned long pos,
|
|
T& item
|
|
);
|
|
/*!
|
|
requires
|
|
- there is an item in the tree associated with pos
|
|
ensures
|
|
- the element in the tree associated with pos has been removed
|
|
and put into #item
|
|
- the convention is still satisfied
|
|
- returns false if the height of the tree has not changed
|
|
- returns true if the height of the tree has shrunk by one
|
|
!*/
|
|
|
|
const T& return_reference (
|
|
const node* t,
|
|
unsigned long pos
|
|
) const;
|
|
/*!
|
|
requires
|
|
- there is an item in the tree associated with pos
|
|
ensures
|
|
- returns a const reference to the item in the tree associated with pos
|
|
!*/
|
|
|
|
T& return_reference (
|
|
node* t,
|
|
unsigned long pos
|
|
);
|
|
/*!
|
|
requires
|
|
- there is an item in the tree associated with pos
|
|
ensures
|
|
- returns a non-const reference to the item in the tree associated
|
|
with pos
|
|
!*/
|
|
|
|
inline bool keep_node_balanced (
|
|
node*& t
|
|
);
|
|
/*!
|
|
requires
|
|
- t != 0
|
|
ensures
|
|
- if (t->balance is < 1 or > 1) then
|
|
- keep_node_balanced() will ensure that t->balance == 0, -1, or 1
|
|
- returns true if it made the tree one height shorter
|
|
- returns false if it didn't change the height
|
|
!*/
|
|
|
|
void push (
|
|
node* n
|
|
) const { stack[stack_pos] = n; ++stack_pos; }
|
|
/*!
|
|
ensures
|
|
- pushes n onto the stack
|
|
!*/
|
|
|
|
|
|
node* pop (
|
|
) const { --stack_pos; return stack[stack_pos]; }
|
|
/*!
|
|
ensures
|
|
- pops the top of the stack and returns it
|
|
!*/
|
|
|
|
// data members
|
|
typename mem_manager::template rebind<node>::other pool;
|
|
typename mem_manager::template rebind<node*>::other ppool;
|
|
|
|
node* tree_root;
|
|
unsigned long tree_size;
|
|
|
|
mutable node** stack;
|
|
mutable node* current_element;
|
|
mutable bool at_start_;
|
|
mutable unsigned char stack_pos;
|
|
|
|
// restricted functions
|
|
sequence_kernel_1(sequence_kernel_1&); // copy constructor
|
|
sequence_kernel_1& operator=(sequence_kernel_1&); // assignment operator
|
|
|
|
};
|
|
|
|
template <
|
|
typename T,
|
|
typename mem_manager
|
|
>
|
|
inline void swap (
|
|
sequence_kernel_1<T,mem_manager>& a,
|
|
sequence_kernel_1<T,mem_manager>& b
|
|
) { a.swap(b); }
|
|
|
|
template <
|
|
typename T,
|
|
typename mem_manager
|
|
>
|
|
void deserialize (
|
|
sequence_kernel_1<T,mem_manager>& item,
|
|
std::istream& in
|
|
)
|
|
{
|
|
try
|
|
{
|
|
item.clear();
|
|
unsigned long size;
|
|
deserialize(size,in);
|
|
T temp;
|
|
for (unsigned long i = 0; i < size; ++i)
|
|
{
|
|
deserialize(temp,in);
|
|
item.add(i,temp);
|
|
}
|
|
}
|
|
catch (serialization_error& e)
|
|
{
|
|
item.clear();
|
|
throw serialization_error(e.info + "\n while deserializing object of type sequence_kernel_1");
|
|
}
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------------------
|
|
// ----------------------------------------------------------------------------------------
|
|
// member function definitions
|
|
// ----------------------------------------------------------------------------------------
|
|
// ----------------------------------------------------------------------------------------
|
|
|
|
template <
|
|
typename T,
|
|
typename mem_manager
|
|
>
|
|
sequence_kernel_1<T,mem_manager>::
|
|
~sequence_kernel_1 (
|
|
)
|
|
{
|
|
ppool.deallocate_array(stack);
|
|
if (tree_size > 0)
|
|
{
|
|
delete_nodes(tree_root);
|
|
}
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------------------
|
|
template <
|
|
typename T,
|
|
typename mem_manager
|
|
>
|
|
void sequence_kernel_1<T,mem_manager>::
|
|
swap (
|
|
sequence_kernel_1<T,mem_manager>& item
|
|
)
|
|
{
|
|
exchange(stack,item.stack);
|
|
exchange(stack_pos,item.stack_pos);
|
|
|
|
pool.swap(item.pool);
|
|
ppool.swap(item.ppool);
|
|
|
|
node* tree_root_temp = item.tree_root;
|
|
unsigned long tree_size_temp = item.tree_size;
|
|
node* current_element_temp = item.current_element;
|
|
bool at_start_temp = item.at_start_;
|
|
|
|
item.tree_root = tree_root;
|
|
item.tree_size = tree_size;
|
|
item.current_element = current_element;
|
|
item.at_start_ = at_start_;
|
|
|
|
tree_root = tree_root_temp;
|
|
tree_size = tree_size_temp;
|
|
current_element = current_element_temp;
|
|
at_start_ = at_start_temp;
|
|
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------------------
|
|
|
|
template <
|
|
typename T,
|
|
typename mem_manager
|
|
>
|
|
size_t sequence_kernel_1<T,mem_manager>::
|
|
size (
|
|
) const
|
|
{
|
|
return tree_size;
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------------------
|
|
|
|
template <
|
|
typename T,
|
|
typename mem_manager
|
|
>
|
|
const T& sequence_kernel_1<T,mem_manager>::
|
|
operator[] (
|
|
unsigned long pos
|
|
) const
|
|
{
|
|
return return_reference(tree_root,pos);
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------------------
|
|
|
|
template <
|
|
typename T,
|
|
typename mem_manager
|
|
>
|
|
T& sequence_kernel_1<T,mem_manager>::
|
|
operator[] (
|
|
unsigned long pos
|
|
)
|
|
{
|
|
return return_reference(tree_root,pos);
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------------------
|
|
|
|
template <
|
|
typename T,
|
|
typename mem_manager
|
|
>
|
|
void sequence_kernel_1<T,mem_manager>::
|
|
add (
|
|
unsigned long pos,
|
|
T& item
|
|
)
|
|
{
|
|
add_to_tree(tree_root,pos,item);
|
|
++tree_size;
|
|
// reset the enumerator
|
|
reset();
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------------------
|
|
|
|
template <
|
|
typename T,
|
|
typename mem_manager
|
|
>
|
|
void sequence_kernel_1<T,mem_manager>::
|
|
remove (
|
|
unsigned long pos,
|
|
T& item
|
|
)
|
|
{
|
|
remove_from_tree(tree_root,pos,item);
|
|
--tree_size;
|
|
// reset the enumerator
|
|
reset();
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------------------
|
|
|
|
template <
|
|
typename T,
|
|
typename mem_manager
|
|
>
|
|
void sequence_kernel_1<T,mem_manager>::
|
|
cat (
|
|
sequence_kernel_1<T,mem_manager>& item
|
|
)
|
|
{
|
|
for (unsigned long i = 0; i < item.tree_size; ++i)
|
|
{
|
|
add_to_tree(
|
|
tree_root,
|
|
tree_size,
|
|
return_reference(item.tree_root,i)
|
|
);
|
|
|
|
++tree_size;
|
|
}
|
|
|
|
item.clear();
|
|
// reset the enumerator
|
|
reset();
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------------------
|
|
|
|
template <
|
|
typename T,
|
|
typename mem_manager
|
|
>
|
|
void sequence_kernel_1<T,mem_manager>::
|
|
clear (
|
|
)
|
|
{
|
|
if (tree_size > 0)
|
|
{
|
|
delete_nodes(tree_root);
|
|
tree_root = 0;
|
|
tree_size = 0;
|
|
}
|
|
// reset the enumerator
|
|
reset();
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------------------
|
|
// ----------------------------------------------------------------------------------------
|
|
// enumerable function definitions
|
|
// ----------------------------------------------------------------------------------------
|
|
// ----------------------------------------------------------------------------------------
|
|
|
|
template <
|
|
typename T,
|
|
typename mem_manager
|
|
>
|
|
bool sequence_kernel_1<T,mem_manager>::
|
|
at_start (
|
|
) const
|
|
{
|
|
return at_start_;
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------------------
|
|
|
|
template <
|
|
typename T,
|
|
typename mem_manager
|
|
>
|
|
void sequence_kernel_1<T,mem_manager>::
|
|
reset (
|
|
) const
|
|
{
|
|
at_start_ = true;
|
|
current_element = 0;
|
|
stack_pos = 0;
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------------------
|
|
|
|
template <
|
|
typename T,
|
|
typename mem_manager
|
|
>
|
|
bool sequence_kernel_1<T,mem_manager>::
|
|
current_element_valid (
|
|
) const
|
|
{
|
|
return (current_element != 0);
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------------------
|
|
|
|
template <
|
|
typename T,
|
|
typename mem_manager
|
|
>
|
|
const T& sequence_kernel_1<T,mem_manager>::
|
|
element (
|
|
) const
|
|
{
|
|
return current_element->item;
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------------------
|
|
|
|
template <
|
|
typename T,
|
|
typename mem_manager
|
|
>
|
|
T& sequence_kernel_1<T,mem_manager>::
|
|
element (
|
|
)
|
|
{
|
|
return current_element->item;
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------------------
|
|
|
|
template <
|
|
typename T,
|
|
typename mem_manager
|
|
>
|
|
bool sequence_kernel_1<T,mem_manager>::
|
|
move_next (
|
|
) const
|
|
{
|
|
// if we haven't started iterating yet
|
|
if (at_start_)
|
|
{
|
|
at_start_ = false;
|
|
if (tree_size == 0)
|
|
{
|
|
return false;
|
|
}
|
|
else
|
|
{
|
|
// find the first element in the tree
|
|
current_element = tree_root;
|
|
node* temp = current_element->left;
|
|
while (temp != 0)
|
|
{
|
|
push(current_element);
|
|
current_element = temp;
|
|
temp = current_element->left;
|
|
}
|
|
return true;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (current_element == 0)
|
|
{
|
|
return false;
|
|
}
|
|
else
|
|
{
|
|
node* temp;
|
|
bool went_up; // true if we went up the tree from a child node to parent
|
|
bool from_left = false; // true if we went up and were coming from a left child node
|
|
// find the next element in the tree
|
|
if (current_element->right != 0)
|
|
{
|
|
// go right and down
|
|
temp = current_element;
|
|
push(current_element);
|
|
current_element = temp->right;
|
|
went_up = false;
|
|
}
|
|
else
|
|
{
|
|
// go up to the parent if we can
|
|
if (current_element == tree_root)
|
|
{
|
|
// in this case we have iterated over all the element of the tree
|
|
current_element = 0;
|
|
return false;
|
|
}
|
|
went_up = true;
|
|
node* parent = pop();
|
|
|
|
|
|
from_left = (parent->left == current_element);
|
|
// go up to parent
|
|
current_element = parent;
|
|
}
|
|
|
|
|
|
while (true)
|
|
{
|
|
if (went_up)
|
|
{
|
|
if (from_left)
|
|
{
|
|
// in this case we have found the next node
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
if (current_element == tree_root)
|
|
{
|
|
// in this case we have iterated over all the elements
|
|
// in the tree
|
|
current_element = 0;
|
|
return false;
|
|
}
|
|
// we should go up
|
|
node* parent = pop();
|
|
from_left = (parent->left == current_element);
|
|
current_element = parent;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// we just went down to a child node
|
|
if (current_element->left != 0)
|
|
{
|
|
// go left
|
|
went_up = false;
|
|
temp = current_element;
|
|
push(current_element);
|
|
current_element = temp->left;
|
|
}
|
|
else
|
|
{
|
|
// if there is no left child then we have found the next node
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------------------
|
|
// ----------------------------------------------------------------------------------------
|
|
// remover function definitions
|
|
// ----------------------------------------------------------------------------------------
|
|
// ----------------------------------------------------------------------------------------
|
|
|
|
template <
|
|
typename T,
|
|
typename mem_manager
|
|
>
|
|
void sequence_kernel_1<T,mem_manager>::
|
|
remove_any (
|
|
T& item
|
|
)
|
|
{
|
|
remove(0,item);
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------------------
|
|
// ----------------------------------------------------------------------------------------
|
|
// private member function definitions
|
|
// ----------------------------------------------------------------------------------------
|
|
// ----------------------------------------------------------------------------------------
|
|
|
|
template <
|
|
typename T,
|
|
typename mem_manager
|
|
>
|
|
void sequence_kernel_1<T,mem_manager>::
|
|
rotate_left (
|
|
node*& t
|
|
)
|
|
{
|
|
|
|
// set the new balance numbers
|
|
if (t->right->balance == 1)
|
|
{
|
|
t->balance = 0;
|
|
t->right->balance = 0;
|
|
}
|
|
else
|
|
{
|
|
t->balance = 1;
|
|
t->right->balance = -1;
|
|
}
|
|
|
|
// perform the rotation
|
|
node* temp = t->right;
|
|
t->right = temp->left;
|
|
temp->left = t;
|
|
t = temp;
|
|
|
|
|
|
// set left_size to its correct value
|
|
t->left_size += t->left->left_size + 1;
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------------------
|
|
|
|
template <
|
|
typename T,
|
|
typename mem_manager
|
|
>
|
|
void sequence_kernel_1<T,mem_manager>::
|
|
rotate_right (
|
|
node*& t
|
|
)
|
|
{
|
|
// set the new balance numbers
|
|
if (t->left->balance == -1)
|
|
{
|
|
t->balance = 0;
|
|
t->left->balance = 0;
|
|
}
|
|
else
|
|
{
|
|
t->balance = -1;
|
|
t->left->balance = 1;
|
|
}
|
|
|
|
// preform the rotation
|
|
node* temp = t->left;
|
|
t->left = temp->right;
|
|
temp->right = t;
|
|
t = temp;
|
|
|
|
|
|
// set left_size to its correct value
|
|
t->right->left_size -= t->left_size + 1;
|
|
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------------------
|
|
|
|
template <
|
|
typename T,
|
|
typename mem_manager
|
|
>
|
|
void sequence_kernel_1<T,mem_manager>::
|
|
double_rotate_right (
|
|
node*& t
|
|
)
|
|
{
|
|
|
|
node* temp = t;
|
|
t = t->left->right;
|
|
|
|
temp->left->right = t->left;
|
|
t->left = temp->left;
|
|
|
|
temp->left = t->right;
|
|
t->right = temp;
|
|
|
|
if (t->balance < 0)
|
|
{
|
|
t->left->balance = 0;
|
|
t->right->balance = 1;
|
|
}
|
|
else if (t->balance > 0)
|
|
{
|
|
t->left->balance = -1;
|
|
t->right->balance = 0;
|
|
}
|
|
else
|
|
{
|
|
t->left->balance = 0;
|
|
t->right->balance = 0;
|
|
}
|
|
t->balance = 0;
|
|
|
|
|
|
// set left_size to its correct value
|
|
t->left_size += t->left->left_size + 1;
|
|
t->right->left_size -= t->left_size + 1;
|
|
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------------------
|
|
|
|
template <
|
|
typename T,
|
|
typename mem_manager
|
|
>
|
|
void sequence_kernel_1<T,mem_manager>::
|
|
double_rotate_left (
|
|
node*& t
|
|
)
|
|
{
|
|
node* temp = t;
|
|
t = t->right->left;
|
|
|
|
temp->right->left = t->right;
|
|
t->right = temp->right;
|
|
|
|
temp->right = t->left;
|
|
t->left = temp;
|
|
|
|
if (t->balance < 0)
|
|
{
|
|
t->left->balance = 0;
|
|
t->right->balance = 1;
|
|
}
|
|
else if (t->balance > 0)
|
|
{
|
|
t->left->balance = -1;
|
|
t->right->balance = 0;
|
|
}
|
|
else
|
|
{
|
|
t->left->balance = 0;
|
|
t->right->balance = 0;
|
|
}
|
|
|
|
t->balance = 0;
|
|
|
|
// set left_size to its correct value
|
|
t->right->left_size -= t->left_size + 1;
|
|
t->left_size += t->left->left_size + 1;
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------------------
|
|
|
|
template <
|
|
typename T,
|
|
typename mem_manager
|
|
>
|
|
bool sequence_kernel_1<T,mem_manager>::
|
|
remove_least_element_in_tree (
|
|
node*& t,
|
|
T& item
|
|
)
|
|
{
|
|
// make a reference to the current node so we don't have to dereference
|
|
// a pointer a bunch of times
|
|
node& tree = *t;
|
|
|
|
// if the left tree is an empty tree
|
|
if ( tree.left == 0)
|
|
{
|
|
// swap nodes element into item
|
|
exchange(tree.item,item);
|
|
|
|
// plug hole left by removing this node
|
|
t = tree.right;
|
|
|
|
// delete the node that was just removed
|
|
tree.right = 0;
|
|
delete_nodes(&tree);
|
|
|
|
// return that the height of this part of the tree has decreased
|
|
return true;
|
|
}
|
|
else
|
|
{
|
|
// subtract one from the left size
|
|
--tree.left_size;
|
|
|
|
// keep going left
|
|
|
|
// if remove made the tree one height shorter
|
|
if ( remove_least_element_in_tree(tree.left,item) )
|
|
{
|
|
// if this caused the current tree to strink then report that
|
|
if ( tree.balance == -1)
|
|
{
|
|
++tree.balance;
|
|
return true;
|
|
}
|
|
else
|
|
{
|
|
++tree.balance;
|
|
return keep_node_balanced(t);
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------------------
|
|
|
|
template <
|
|
typename T,
|
|
typename mem_manager
|
|
>
|
|
bool sequence_kernel_1<T,mem_manager>::
|
|
add_to_tree (
|
|
node*& t,
|
|
unsigned long pos,
|
|
T& item
|
|
)
|
|
{
|
|
// if found place to add
|
|
if (t == 0)
|
|
{
|
|
// create a node to add new item into
|
|
t = pool.allocate();
|
|
|
|
// make a reference to the current node so we don't have to dereference
|
|
// a pointer a bunch of times
|
|
node& tree = *t;
|
|
|
|
|
|
// set left and right pointers to 0 to indicate that there are no
|
|
// left or right subtrees
|
|
tree.left = 0;
|
|
tree.right = 0;
|
|
tree.balance = 0;
|
|
tree.left_size = 0;
|
|
|
|
// put item into t
|
|
exchange(item,tree.item);
|
|
|
|
// indicate that the height of this tree has increased
|
|
return true;
|
|
}
|
|
else // keep looking for a place to add the new item
|
|
{
|
|
// make a reference to the current node so we don't have to dereference
|
|
// a pointer a bunch of times
|
|
node& tree = *t;
|
|
signed char old_balance = tree.balance;
|
|
|
|
// add the new item to whatever subtree it should go into
|
|
if ( pos < tree.left_size + 1 )
|
|
{
|
|
tree.balance -= add_to_tree(tree.left,pos,item);
|
|
++tree.left_size;
|
|
}
|
|
else
|
|
tree.balance += add_to_tree(tree.right,pos - tree.left_size - 1,item);
|
|
|
|
|
|
// if the tree was balanced to start with
|
|
if (old_balance == 0)
|
|
{
|
|
// if its not balanced anymore then it grew in height
|
|
if (tree.balance != 0)
|
|
return true;
|
|
else
|
|
return false;
|
|
}
|
|
else
|
|
{
|
|
// if the tree is now balanced then it didn't grow
|
|
if (tree.balance == 0)
|
|
{
|
|
return false;
|
|
}
|
|
else
|
|
{
|
|
// if the tree needs to be balanced
|
|
if (tree.balance != old_balance)
|
|
{
|
|
return !keep_node_balanced(t);
|
|
}
|
|
// if there has been no change in the heights
|
|
else
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------------------
|
|
|
|
template <
|
|
typename T,
|
|
typename mem_manager
|
|
>
|
|
bool sequence_kernel_1<T,mem_manager>::
|
|
remove_from_tree (
|
|
node*& t,
|
|
unsigned long pos,
|
|
T& item
|
|
)
|
|
{
|
|
|
|
// make a reference to the current node so we don't have to dereference
|
|
// a pointer a bunch of times
|
|
node& tree = *t;
|
|
|
|
// if item is on the left
|
|
if (pos < tree.left_size)
|
|
{
|
|
// adjust the left size
|
|
--tree.left_size;
|
|
|
|
// if the left side of the tree has the greatest height
|
|
if (tree.balance == -1)
|
|
{
|
|
tree.balance += remove_from_tree(tree.left,pos,item);
|
|
return !tree.balance;
|
|
}
|
|
else
|
|
{
|
|
tree.balance += remove_from_tree(tree.left,pos,item);
|
|
return keep_node_balanced(t);
|
|
}
|
|
|
|
}
|
|
// if item is found
|
|
else if (pos == tree.left_size)
|
|
{
|
|
// if there is no left node
|
|
if (tree.left == 0)
|
|
{
|
|
// swap nodes element into item
|
|
exchange(tree.item,item);
|
|
|
|
// plug hole left by removing this node and free memory
|
|
t = tree.right; // plug hole with right subtree
|
|
|
|
// delete old node
|
|
tree.right = 0;
|
|
delete_nodes(&tree);
|
|
|
|
// indicate that the height has changed
|
|
return true;
|
|
}
|
|
// if there is no right node
|
|
else if (tree.right == 0)
|
|
{
|
|
// swap nodes element into item
|
|
exchange(tree.item,item);
|
|
|
|
// plug hole left by removing this node and free memory
|
|
t = tree.left; // plug hole with left subtree
|
|
|
|
// delete old node
|
|
tree.left = 0;
|
|
delete_nodes(&tree);
|
|
|
|
// indicate that the height of this tree has changed
|
|
return true;
|
|
}
|
|
// if there are both a left and right sub node
|
|
else
|
|
{
|
|
// get an element that can replace the one being removed and do this
|
|
// if it made the right subtree shrink by one
|
|
if (remove_least_element_in_tree(tree.right,item))
|
|
{
|
|
// adjust the tree height
|
|
--tree.balance;
|
|
|
|
// put the element into item copy and also plug the
|
|
// hole with the smallest element from the right.
|
|
exchange(item,tree.item);
|
|
|
|
// if the height of the current tree has dropped by one
|
|
if (tree.balance == 0)
|
|
{
|
|
return true;
|
|
}
|
|
else
|
|
{
|
|
return keep_node_balanced(t);
|
|
}
|
|
}
|
|
// else this remove did not effect the height of this tree
|
|
else
|
|
{
|
|
// put the element into item copy and also plug the
|
|
// hole with the smallest element from the right.
|
|
exchange(item,tree.item);
|
|
|
|
return false;
|
|
}
|
|
|
|
}
|
|
}
|
|
// if item is on the right
|
|
else
|
|
{
|
|
|
|
// if the right side of the tree has the greatest height
|
|
if (tree.balance == 1)
|
|
{
|
|
tree.balance -= remove_from_tree(tree.right,pos - tree.left_size - 1,item);
|
|
return !tree.balance;
|
|
}
|
|
else
|
|
{
|
|
tree.balance -= remove_from_tree(tree.right,pos - tree.left_size - 1,item);
|
|
return keep_node_balanced(t);
|
|
}
|
|
}
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------------------
|
|
|
|
template <
|
|
typename T,
|
|
typename mem_manager
|
|
>
|
|
T& sequence_kernel_1<T,mem_manager>::
|
|
return_reference (
|
|
node* t,
|
|
unsigned long pos
|
|
)
|
|
{
|
|
while (true)
|
|
{
|
|
// if we have found the node
|
|
if (pos == t->left_size)
|
|
return t->item;
|
|
|
|
if (pos < t->left_size)
|
|
{
|
|
// go left
|
|
t = t->left;
|
|
}
|
|
else
|
|
{
|
|
// go right
|
|
pos -= t->left_size+1;
|
|
t = t->right;
|
|
}
|
|
}
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------------------
|
|
|
|
template <
|
|
typename T,
|
|
typename mem_manager
|
|
>
|
|
const T& sequence_kernel_1<T,mem_manager>::
|
|
return_reference (
|
|
const node* t,
|
|
unsigned long pos
|
|
) const
|
|
{
|
|
while (true)
|
|
{
|
|
// if we have found the node
|
|
if (pos == t->left_size)
|
|
return t->item;
|
|
|
|
if (pos < t->left_size)
|
|
{
|
|
// go left
|
|
t = t->left;
|
|
}
|
|
else
|
|
{
|
|
// go right
|
|
pos -= t->left_size+1;
|
|
t = t->right;
|
|
}
|
|
}
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------------------
|
|
|
|
template <
|
|
typename T,
|
|
typename mem_manager
|
|
>
|
|
bool sequence_kernel_1<T,mem_manager>::
|
|
keep_node_balanced (
|
|
node*& t
|
|
)
|
|
{
|
|
// make a reference to the current node so we don't have to dereference
|
|
// a pointer a bunch of times
|
|
node& tree = *t;
|
|
|
|
// if tree does not need to be balanced then return false
|
|
if (tree.balance == 0)
|
|
return false;
|
|
|
|
|
|
// if tree needs to be rotated left
|
|
if (tree.balance == 2)
|
|
{
|
|
if (tree.right->balance >= 0)
|
|
rotate_left(t);
|
|
else
|
|
double_rotate_left(t);
|
|
}
|
|
// else if the tree needs to be rotated right
|
|
else if (tree.balance == -2)
|
|
{
|
|
if (tree.left->balance <= 0)
|
|
rotate_right(t);
|
|
else
|
|
double_rotate_right(t);
|
|
}
|
|
|
|
|
|
if (t->balance == 0)
|
|
return true;
|
|
else
|
|
return false;
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------------------
|
|
|
|
template <
|
|
typename T,
|
|
typename mem_manager
|
|
>
|
|
void sequence_kernel_1<T,mem_manager>::
|
|
delete_nodes (
|
|
node* t
|
|
)
|
|
{
|
|
if (t->left)
|
|
delete_nodes(t->left);
|
|
if (t->right)
|
|
delete_nodes(t->right);
|
|
pool.deallocate(t);
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------------------
|
|
}
|
|
|
|
#endif // DLIB_SEQUENCE_KERNEl_1_
|
|
|