Please send questions to
st10@humboldt.edu .
/************************************************************/
/* ADAPTED FROM: */
/* http://www.cs.colorado.edu/~main/chapter4/node1.cxx */
/* */
/* Main and Savitch, "Data Structures and Other Objects */
/* using C++", 2nd edition, Addison-Wesley, Ch.5 */
/************************************************************/
//---------------------------------------------------------------------
// File: node1.cpp
// Name: Michael Main, Walter Savitch
// (adapted by Sharon M. Tuttle)
// last modified: 3-2-05
//
// Class name: node
//
// Purpose: serves as the unit from which a singly-linked list
// can be built.
//
// Also included in this file are a collection of
// useful list-manipulation functions, called the
// "linked list toolkit"
//
// DYNAMIC MEMORY USAGE by the node class and linked list toolkit:
// If there is insufficient dynamic memory, then the
// following functions throw bad_alloc:
// the contructors,
// list_head_insert, list_insert, list_copy, list_piece
//
// NOTE:
// Some of the methods and functions have return value that is
// a pointer to a node. Each of these functions comes in TWO
// versions: a non-const version (where the return value is
// node*) and a const version (where the return value is
// const node*).
//---------------------------------------------------------------------
#include <cassert>
#include "node1.h"
using namespace std;
/*****************************************************/
/* CONSTRUCTORS and DESTRUCTOR */
/*****************************************************/
//---------------------------------------------------------------------
// postcondition: creates a node with data_field obtained from
// the default constructor of the value_type, and
// next_field set to NULL.
//
// NOTE: In the ANSI/ISO standard, this default-constructor
// notation is also allowed for the built-in types,
// providing a default value of zero.
//
node::node( )
{
data_field = value_type();
next_field = NULL;
}
//---------------------------------------------------------------------
// postcondition: creates a node with data_field set to
// init_data, and next_field set to NULL.
//
node::node(const value_type& init_data)
{
data_field = init_data;
next_field = NULL;
}
//---------------------------------------------------------------------
// postcondition: create a node with data_field obtained from
// the default constructor of the value_type, and
// next_field set to init_next.
//
node::node(node* init_next)
{
data_field = value_type();
next_field = init_next;
}
//---------------------------------------------------------------------
// postcondition: create a node with data_field set to
// init_data, and next_field set to init_next.
//
node::node(const value_type& init_data, node* init_next)
{
data_field = init_data;
next_field = init_next;
}
/*************************************************************/
/* ACCESSORS and other constant member functions (observers) */
/*************************************************************/
//---------------------------------------------------------------------
// postcondition: returns the data from this node
//
node::value_type node::get_data( ) const
{
return data_field;
}
//---------------------------------------------------------------------
// postcondition: returns the next pointer from this node.
// (See note above --- need both a const and non-const
// version of this, because it returns a pointer.
// See also pp. 219-221 of Savitch and Main, 3rd edition.)
//
const node* node::get_next( ) const
{
return next_field;
}
node* node::get_next( )
{
return next_field;
}
/*****************************************************/
/* MODIFIERS and other modifying member functions */
/*****************************************************/
//---------------------------------------------------------------------
// postcondition: the node now contains the specified
// new_data.
//
void node::set_data(const value_type& new_data)
{
data_field = new_data;
}
//---------------------------------------------------------------------
// postcondition: the node now contains the specified
// new_next pointer.
//
void node::set_next(node* new_next)
{
next_field = new_next;
}
/****************************************************/
/* NONMEMBER FUNCTIONS for the node class */
/****************************************************/
//----------------------------------------------
// HERE, these are functions for the so-called
// LINKED LIST TOOLKIT.
//----------------------------------------------
//---------------------------------------------------------------------
// function: list_length
//
// preconditions: head_ptr is the head pointer of a linked list
//
// postconditions: the value returned in the number of nodes in
// the linked list
//
// Examples: if node* begin_ptr is the first node in a linked list of
// 3 nodes, then:
// list_length(begin_ptr) == 3
// if node* empty_ptr = NULL,
// list_length(empty_ptr) == 0
//
size_t list_length(const node* head_ptr)
{
const node *cursor;
size_t answer;
answer = 0;
for (cursor = head_ptr; cursor != NULL; cursor = cursor->get_next( ))
{
answer++;
}
return answer;
}
//---------------------------------------------------------------------
// function: list_head_insert
//
// preconditions: head_ptr is the head pointer of a linked list.
//
// postconditions:
// * a new node containing the given entry has been
// added at the head of the linked list;
// * head_ptr now points to the head of the new, longer
// linked list
//
// Examples: if node* begin_ptr points to a list containing 8 2 7,
// and value_type is int,
// then list_head_insert(begin_ptr, 5)
// results in a list containing 5 8 2 7;
// that is, begin_ptr->get_data( ) == 5,
// list_length(begin_ptr) == 4
// if node* empty_ptr = NULL,
// then list_head_insert(empty_ptr, 5)
// results in a list containing 5;
// that is, empty_ptr->get_data( ) == 5,
// list_length(empty_ptr) == 1
//
void list_head_insert(node*& head_ptr, const node::value_type& entry)
{
node* temp;
temp = new node(entry);
// temp will be pointing to the new first node --- so
// this new node's next_field should be pointing
// to the OLD first node...
//
temp->set_next(head_ptr);
// and now it is safe to reset head_ptr to its new first node
head_ptr = temp;
}
//---------------------------------------------------------------------
// function: list_insert
//
// preconditions: previous_ptr points to a node in a linked list.
//
// postconditions: a new node containing the given entry has been added
// after the node that previous_ptr points to.
//
// Examples: if you have a linked list 8 5 2 7,
// and prev_ptr points to the node containing 8,
// then list_insert(prev_ptr, 9) results in the list 8 9 5 2 7,
// and prev_ptr->get_next()->get_data() == 9;
// if prev_ptr2 points to the node containing 7,
// then list_insert(prev_ptr2, 6) results in the list 8 9 5 2 7 6,
// and prev_ptr->get_next()->get_data() == 6;
// if prev_ptr3 points to the node containing 5,
// then list_insert(prev_ptr3, 4) results in the list 8 9 5 4 2 7 6,
// and prev_ptr->get_next()->get_data() == 4;
//
void list_insert(node* previous_ptr, const node::value_type& entry)
{
node *insert_ptr;
insert_ptr = new node(entry);
// newly-inserted node needs to point to the one AFTER
// the previous_ptr's node;
insert_ptr->set_next(previous_ptr->get_next( ));
// now, the previous_ptr's node needs to now know that
// the NEW node comes next after it;
previous_ptr->set_next(insert_ptr);
}
//---------------------------------------------------------------------
// function: list_search
// (See note above --- need both a const and non-const version
// of this, because it returns a pointer.
// See also pp. 219-221 of Savitch and Main, 3rd edition.)
//
// preconditions: head_ptr is the head pointer of a linked list
//
// postconditions: the pointer returned points to the first node containing
// the specified target in its data member. If there is no such node,
// the NULL pointer is returned.
//
// Examples: for the linked list containing 8 5 2 7 8 10,
// assuming that node* begin_ptr points to its head, and
// assuming that node* result_ptr,
// if result_ptr = list_search(begin_ptr, 8),
// then result_ptr->get_data() == 8
// if result_ptr = list_search(begin_ptr, 10),
// then result_ptr->get_data() == 10
// if result_ptr = list_search(begin_ptr, 2),
// then result_ptr->get_data() == 2
// if result_ptr = list_search(begin_ptr, 13),
// then result_ptr == NULL
//
node* list_search(node* head_ptr, const node::value_type& target)
{
node *cursor;
for (cursor = head_ptr; cursor != NULL; cursor = cursor->get_next( ))
{
if (target == cursor->get_data( ))
{
return cursor;
}
}
// if REACH here (didn't return in loop), then target NOT in list
return NULL;
}
const node* list_search(const node* head_ptr,
const node::value_type& target)
{
const node *cursor;
for (cursor = head_ptr; cursor != NULL; cursor = cursor->get_next( ))
{
if (target == cursor->get_data( ))
{
return cursor;
}
}
// if REACH here (didn't return in loop), then target NOT in list
return NULL;
}
//---------------------------------------------------------------------
// function: list_locate
// (See note above --- need both a const and non-const version
// of this, because it returns a pointer.
// See also pp. 219-221 of Savitch and Main, 3rd edition.)
//
// preconditions:
// * head_ptr is the head pointer of a linked list
// * position > 0
//
// postconditions:
// * The pointer returned points to the node at the specified
// position in the list. (The head node is position 1, the next node
// is position 2, and so on.)
// * If there is no such position, then the NULL pointer is returned.
//
// Examples: for the linked list containing 8 5 2 7 8 10,
// assuming that node* begin_ptr points to its head, and
// assuming that node* result_ptr,
// if result_ptr = list_search(begin_ptr, 1),
// then result_ptr->get_data() == 8
// if result_ptr = list_search(begin_ptr, 6),
// then result_ptr->get_data() == 10
// if result_ptr = list_search(begin_ptr, 3),
// then result_ptr->get_data() == 2
// if result_ptr = list_search(begin_ptr, 13),
// then result_ptr == NULL
//
node* list_locate(node* head_ptr, size_t position)
{
node *cursor;
size_t i;
assert (position > 0);
cursor = head_ptr;
// remember: head of list is position 1, in THIS function!!!
for (i = 1; (i < position) && (cursor != NULL); i++)
{
cursor = cursor->get_next( );
}
return cursor;
}
const node* list_locate(const node* head_ptr, size_t position)
{
const node *cursor;
size_t i;
assert (position > 0);
cursor = head_ptr;
// remember: head of list is position 1, in THIS function!!!
for (i = 1; (i < position) && (cursor != NULL); i++)
{
cursor = cursor->get_next( );
}
return cursor;
}
//---------------------------------------------------------------------
// function: list_head_remove
//
// preconditions: head_ptr is the head pointer of a linked list with
// at least one node;
//
// postconditions:
// * the head node has been removed and returned to the heap;
// * head_ptr is now the head pointer of the new, shorter linked
// list
//
// Examples: for the linked list containing 8 5 2 7,
// assuming that node* begin_ptr points to its head,
// then list_head_remove(begin_ptr) results in the linked
// list 5 2 7,
// and list_length(begin_ptr) == 3,
// and begin_ptr->get_data() == 5.
// for the linked list containing 13,
// assuming that begin_ptr2 points to its head,
// then list_head_remove(begin_ptr2) results in an empty list,
// and list_length(begin_ptr) == 0,
// and begin_ptr == NULL
//
void list_head_remove(node*& head_ptr)
{
node *remove_ptr;
remove_ptr = head_ptr;
head_ptr = head_ptr->get_next( );
delete remove_ptr;
}
//---------------------------------------------------------------------
// function: list_remove
//
// preconditions: previous_ptr points to a node in a linked list, and this
// is NOT the tail node of the list.
//
// postconditions: The node *after* previous_ptr has been removed from
// the linked list.
//
// Examples: for the linked list containing 8 5 2 7 8 10,
// assuming that node* begin_ptr points to its head,
// then list_remove(begin_ptr) results in the linked
// list 8 2 7 8 10,
// and list_length(begin_ptr) == 5,
// and begin_ptr->get_next()->get_data() == 2;
// for the linked list containing 8 2 7 8 10,
// assuming that prev_ptr2 points to the node containing 7,
// and begin_ptr points to its head,
// then list_remove(prev_ptr2) results in the list 8 2 7 10,
// and list_length(begin_ptr) == 4,
// and prev_ptr2->get_next()->get_data() == 10;
// for the linked list containing 8 2 7 10,
// assuming that prev_ptr2 points to the node containing 7,
// and begin_ptr points to its head,
// then list_remove(prev_ptr2) results in the list 8 2 7,
// and list_length(begin_ptr) == 3,
// and prev_ptr2->get_next() == NULL.
//
void list_remove(node* previous_ptr)
{
node *remove_ptr;
remove_ptr = previous_ptr->get_next( );
previous_ptr->set_next( remove_ptr->get_next( ) );
delete remove_ptr;
}
//---------------------------------------------------------------------
// function: list_clear
//
// preconditions: head_ptr is the head pointer of a linked list.
//
// postconditions:
// * all nodes of the list have been returned to the heap;
// * head_ptr is now NULL
//
// Examples: for the linked list containing 8 5 2 7 8 10,
// assuming that node* begin_ptr points to its head,
// then list_clear(begin_ptr) results in an empty linked list,
// and list_length(begin_ptr) == 0,
// and begin_ptr == NULL.
// for an empty linked list,
// assuming that node* begin_ptr2 == NULL,
// then list_clear(begin_ptr2) results in an empty linked list,
// and list_length(begin_ptr2) == 0,
// and begin_ptr2 == NULL.
//
void list_clear(node*& head_ptr)
{
while (head_ptr != NULL)
{
list_head_remove(head_ptr);
}
}
//---------------------------------------------------------------------
// function: list_copy
//
// preconditions: source_ptr is the head_ptr of a linked list
//
// postconditions:
// * head_ptr and tail_ptr are the head and tail pointers for a
// a new list that contains the same items as the list pointed
// to by source_ptr.
// * the original list is unaltered.
//
// Examples: for the linked list containing 8 5 2 7,
// assuming that node* begin_ptr points to its head,
// and node* new_head, node* new_tail have been declared,
// then list_copy(begin_ptr, new_head, new_tail) results in
// a new linked list copy containing 8 5 2 7,
// and list_length(new_head) == 4,
// and new_head->get_data() == 8,
// and new_tail->get_data() == 7;
// for an empty linked list,
// assuming that node* begin_ptr2 == NULL,
// and node* new_head2, node* new_tail2 have been declared,
// then list_copy(begin_ptr2, new_head2, new_tail2) results in
// a new empty linked list,
// and list_length(begin_ptr2) == 0,
// and new_head2 == NULL,
// and new_tail2 == NULL;
// for a linked list containing 13,
// assuming that node* begin_ptr3 points to the beginning of this list,
// and node* new_head3, node* new_tail3 have been declared,
// then list_copy(begin_ptr3, new_head3, new_tail3) results in
// a new linked list containing 13,
// and list_length(begin_ptr3) == 1,
// and new_head3->get_data() = 13,
// and new_tail3->get_data() = 13;
//
void list_copy(const node* source_ptr,
node*& head_ptr, node*& tail_ptr)
{
head_ptr = NULL;
tail_ptr = NULL;
// Handle the case of the empty list.
if (source_ptr == NULL)
{
return;
}
// Make the head node for the newly created list, and put data in it.
list_head_insert(head_ptr, source_ptr->get_data( ));
tail_ptr = head_ptr;
// Copy the rest of the nodes one at a time, adding at the tail
// of new list.
source_ptr = source_ptr->get_next( );
while (source_ptr != NULL)
{
list_insert(tail_ptr, source_ptr->get_data( ));
tail_ptr = tail_ptr->get_next( );
source_ptr = source_ptr->get_next( );
}
}