CS 1704 Introduction to Data Structures and Software

  • Slides: 43
Download presentation
CS 1704 Introduction to Data Structures and Software Engineering

CS 1704 Introduction to Data Structures and Software Engineering

Linked Lists Basics n Arrays have so many drawbacks: – Wasted space – Wasted

Linked Lists Basics n Arrays have so many drawbacks: – Wasted space – Wasted time – Clunky for insertion or deletion in the middle – etc.

Linked-List Basics n Need a better solution n Linked-List n Idea: – Information is

Linked-List Basics n Need a better solution n Linked-List n Idea: – Information is stored in nodes – Each node points to the node directly following it – To find, insert or delete you simply manipulate nodes

Trade-offs Linked lists allow for random insertion and deletion n Search, however, could take

Trade-offs Linked lists allow for random insertion and deletion n Search, however, could take searching the entire list n If an array is ordered, you could search less than half and find what you are seeking n Linked data structures in general allow greater flexibility n

Head Linked List Object Current Tail

Head Linked List Object Current Tail

Specifics n. A linked list contains a head node, a tail node and a

Specifics n. A linked list contains a head node, a tail node and a current node. n These are used to keep track of the data structure n A linked-list class would make these private data. n A linked list should have several different types of insertion and deletion.

Insertion/Deletion n You can have an insert before the head node, an insert after

Insertion/Deletion n You can have an insert before the head node, an insert after the tail node, an insert before the current node and an insert after the current node. n You can think up many more, but should do at least insert before and after the current node. n You should do a remove current node.

Find n Find simply walks down the list of nodes, starting at the head

Find n Find simply walks down the list of nodes, starting at the head node looking for a particular piece of data n When it finds it, it stops and the current node pointer should be pointing to that node

More Specifics n The head, tail and current node pointers are dynamically allocated pointers

More Specifics n The head, tail and current node pointers are dynamically allocated pointers to a node class. n The magic word: dynamic. n That means the linked list class needs to implement a copy constructor, assignment operator and a destructor in addition to any other methods.

Start of a Linked List class Linked. List { public: //stuff private: Node *Head;

Start of a Linked List class Linked. List { public: //stuff private: Node *Head; Node *Tail; Node *Current; };

Question n What is Node? – Node is a class – Node holds or

Question n What is Node? – Node is a class – Node holds or points to the data. – Nodes also point to at least the next node in the chain.

Here’s a node…let’s take a look inside!! Space for the data or a pointer

Here’s a node…let’s take a look inside!! Space for the data or a pointer to the data Pointer to the next node in the chain Usually called Next

Specifics n Nodes should have at least two private pieces of data – A

Specifics n Nodes should have at least two private pieces of data – A place to store the data – A pointer to the next node in the chain n The should support various setting and getting methods of both the next pointer and the data

Node Class start class Node { public: //stuff private: Node* Next; Record* R; };

Node Class start class Node { public: //stuff private: Node* Next; Record* R; };

Issues n Insertion – Insert after current, after tail, and before head is more

Issues n Insertion – Insert after current, after tail, and before head is more or less straight forward – You create a new node – Have the new node point to what you used to point to – Have the node you are sitting in point to the node • In the case of the insert before head, redirect the head pointer to point to the new head • In the case of insert after tail, redirect tail to point to new node • In any case of current, need to check to see if the current is the head or tail and take appropriate actions

Head Current Record to be inserted Tail

Head Current Record to be inserted Tail

Head Current Pointer to New Node Tail

Head Current Pointer to New Node Tail

Head Current New Node NULL Tail

Head Current New Node NULL Tail

More Insertion Issues n n n Insert before current raises a problem How do

More Insertion Issues n n n Insert before current raises a problem How do you get to the node before you? Solution, create a temporary node pointer and walk down from head and look ahead to see if the next node is the current node. When you see the current node ahead of you, stop and insert after the node the temporary pointer is pointing to. Again taking into account if the temporary node is the head or the tail

Deletion Issues n n n Same problem as insert before current How do you

Deletion Issues n n n Same problem as insert before current How do you find the node that is in front of you to be able to hook up the chain again? Use same solution. May want to write a private helper function that finds the node before the current node. You can call it whenever you need. It could return a pointer to you.

Head Current Record to be deleted Tail

Head Current Record to be deleted Tail

Head Current Record before Current Tail

Head Current Record before Current Tail

Head Current Record before Current Tail

Head Current Record before Current Tail

Alternative Create a doubly linked-list. n Each node not only points to the next

Alternative Create a doubly linked-list. n Each node not only points to the next node in the chain, but also the node before it in the chain. n This simplifies the problem of how do you get the node in front of you. n It complicates insertion and deletion because now you have more pointers to keep track of. n

Forward Declarations n We can simply make a forward declaration of Node, prior to

Forward Declarations n We can simply make a forward declaration of Node, prior to defining the Node type: typedef int Item; struct Node; // forward declaration typedef Node* Node. Ptr; struct Node { Item Element; Node. Ptr Next; }; Node. Ptr Head = NULL; // head pointer for list

Node Class class Node { public: Node(); Node( Record *R ); Node( const Node&

Node Class class Node { public: Node(); Node( Record *R ); Node( const Node& RHS); //Copy const Node& operator=( const Node& RHS); ~Node();

More Node * get. Next(); void set. Next( Node * N ); Record get.

More Node * get. Next(); void set. Next( Node * N ); Record get. Data(); void set. Data( Record *R ); private: Node* Next; Record* record. Ptr; };

Node Implementation Node: : Node() { Next = 0; record. Ptr = 0; }

Node Implementation Node: : Node() { Next = 0; record. Ptr = 0; } Node: : Node( Record *R ) { Next = 0; record. Ptr = R; }

Destructor Node: : ~Node() { delete record. Ptr; delete Next; }

Destructor Node: : ~Node() { delete record. Ptr; delete Next; }

assignment Operator const Node& Node: : opertator=( const Node& RHS ) { if (

assignment Operator const Node& Node: : opertator=( const Node& RHS ) { if ( this != &RHS ) { delete Next; delete record. Ptr; Next = 0; record. Ptr = new (nothrow) Record(*RHS. record. Ptr); } return *this; }

get. Next/set. Next Node * Node: : get. Next() { return temp; } void

get. Next/set. Next Node * Node: : get. Next() { return temp; } void Node: : set. Next( Node* N ) { Next = N; }

get. Data/set. Data Record Node: : get. Data() { Record R = *record. Ptr;

get. Data/set. Data Record Node: : get. Data() { Record R = *record. Ptr; return R; } void Node: : set. Data( Record *R ) { record. Ptr = R; }

Some more implementation class Linked. List { public: Linked. List(); Linked. List( const Linked.

Some more implementation class Linked. List { public: Linked. List(); Linked. List( const Linked. List& ); Linked. List operator=( const Linked. List& ); ~Linked. List(); bool insert. After. Current( Record ); bool insert. Before. Current( Record);

More Implementation void goto. Head(); void goto. Tail(); bool find( Record ) const; bool

More Implementation void goto. Head(); void goto. Tail(); bool find( Record ) const; bool delete. Current( ); void print( ostream& ) const; void clear( );

More Implementation private: Node* find. Node. Before. Curr( ); Node* Head; Node* Tail; Node*

More Implementation private: Node* find. Node. Before. Curr( ); Node* Head; Node* Tail; Node* Current; };

Constructor Linked. List: : Linked. List() { Head = Tail = Current = 0;

Constructor Linked. List: : Linked. List() { Head = Tail = Current = 0; }

Destructor Linked. List: : ~Linked. List() { Node* temp = Head; Current = Head;

Destructor Linked. List: : ~Linked. List() { Node* temp = Head; Current = Head; while ( Current != 0 ) { Current = Current->get. Next(); delete Temp; Temp = Current; } Head = Tail = Current = 0; }

insert. After. Current bool Linked. List: : insert. After. Current( Record R ) {

insert. After. Current bool Linked. List: : insert. After. Current( Record R ) { bool success = true; Node* new. Node = new (nothrow) Node( R ); if ( !new. Node ) success = false; else if ( Head == 0 ) { Head = Tail = Current = new. Node; } else { new. Node->set. Next( Current->get. Next() ); Current->set. Next( new. Node); } return success; }

delete. Current bool Linked. List: : delete. Current() { bool success = true; if

delete. Current bool Linked. List: : delete. Current() { bool success = true; if ( Current != Head && Current != Tail ) { Node* prior = find. Node. Before. Current(); prior->set. Next( Current->get. Next() ); delete Current; Current = prior; } return success; }

find. Node. Before. Current Node* Linked. List: : find. Node. Before. Current() { Node*

find. Node. Before. Current Node* Linked. List: : find. Node. Before. Current() { Node* temp = Head; if ( Head == Current ) temp = 0; else { while ( Temp->get. Next() != Current ) Temp = Temp->get. Next() } return temp; }

copy constructor Linked. List: : Linked. List( const Linked. List& LL ) { Head

copy constructor Linked. List: : Linked. List( const Linked. List& LL ) { Head = new Node( new Record( LL. Head->get. Data() ) ); Current = Tail = Head = 0; Node * temp = LL. Head; while ( temp != 0 ) { insert. After. Current( LL. Current->get. Data() ); temp = temp->get. Next() ; } //Is this all? }

copy constructor Linked. List: : Linked. List( const Linked. List& LL ) { Head

copy constructor Linked. List: : Linked. List( const Linked. List& LL ) { Head = new Node( new Record( LL. Head->get. Data() ) ); Current = Tail = Head = 0; Node * temp = LL. Head; while ( temp != 0 ) { insert. After. Current( LL. Current->get. Data() ); temp = temp->get. Next() ; } //Is this all? } //check to see if LL is empty, current should be at the same relative position, set tail

Other Considerations n What about a Merge Method? – Merges two Linked lists

Other Considerations n What about a Merge Method? – Merges two Linked lists