Chapter 3
Double-linked table
After a single-linked table is completed, it is the turn of double-linked tables.
3.1 code implementation
The implementation of double-stranded tables is as follows:
//////////////////////////////////////// ///////////////////////////////////////
//
// Filename: Dlist. h
// Version 0.10
// Author: Luo Cong
// Date: 2005-1-4 10:33:21
// Comment:
//
//////////////////////////////////////// ///////////////////////////////////////
# Ifndef _ double_list_h __
# DEFINE _ double_list_h __
# Include <assert. h>
# Include <crtdbg. h>
# Ifdef _ debug
# Define debug_new new (_ normal_block, this_file, _ line __)
# Endif
# Ifdef _ debug
# Define new debug_new
# UNDEF this_file
Static char this_file [] = _ file __;
# Endif
# Ifdef _ debug
# Ifndef assert
# Define assert
# Endif
# Else // not _ debug
# Ifndef assert
# Define assert
# Endif
# Endif // _ debug
Template <typename T>
Class cNode
{
Public:
T data;
CNode <t> * Prior;
CNode <t> * next;
CNode (): Data (T (), prior (null), next (null ){}
CNode (const T & initdata): Data (initdata), prior (null), next (null ){}
};
Template <typename T>
Class cdlist
{
Protected:
Int m_ncount;
CNode <t> * m_pnodehead;
CNode <t> * m_pnodetail;
Public:
Cdlist ();
Cdlist (const T & initdata );
~ Cdlist ();
Public:
Int isempty () const;
Int getcount () const;
Int insertbefore (const int POs, const t data );
Int insertafter (const int POs, const t data );
Int addhead (const t data );
Int addtail (const t data );
Void removeat (const int POS );
Void removehead ();
Void removetail ();
Void removeall ();
T & gettail ();
T gettail () const;
T & gethead ();
T gethead () const;
T & getat (const int POS );
T getat (const int POS) const;
Void setat (const int POs, t data );
Int find (const t data) const;
T & getprev (Int & Pos );
T & getnext (Int & Pos );
};
Template <typename T>
Inline cdlist <t >:: cdlist (): m_ncount (0), m_pnodehead (null), m_pnodetail (null)
{
}
Template <typename T>
Inline cdlist <t >:: cdlist (const T & initdata)
: M_ncount (0), m_pnodehead (null), m_pnodetail (null)
{
Addhead (initdata );
}
Template <typename T>
Inline cdlist <t> ::~ Cdlist ()
{
Removeall ();
}
Template <typename T>
Inline T & cdlist <t>: getnext (Int & Pos)
{
Assert (0! = M_ncount );
Assert (1 <= POS & Pos <= m_ncount );
Int I;
CNode <t> * ptmpnode = m_pnodehead;
For (I = 1; I <Pos; ++ I)
{
Ptmpnode = ptmpnode-> next;
}
++ Pos;
Return ptmpnode-> data;
}
Template <typename T>
Inline T & cdlist <t>: getprev (Int & Pos)
{
Assert (0! = M_ncount );
Assert (1 <= POS & Pos <= m_ncount );
Int I;
CNode <t> * ptmpnode = m_pnodehead;
For (I = 1; I <Pos; ++ I)
{
Ptmpnode = ptmpnode-> next;
}
-- Pos;
Return ptmpnode-> data;
}
Template <typename T>
Inline int cdlist <t >:: insertbefore (const int POs, const t data)
{
Int I;
Int nretpos;
CNode <t> * ptmpnode;
CNode <t> * pnewnode;
Pnewnode = new cNode <t>;
If (null = pnewnode)
{
Nretpos = 0;
Goto exit0;
}
Pnewnode-> DATA = data;
// If the list is empty, replace the head node with the new node.
If (null = m_pnodehead)
{
Pnewnode-> prior = NULL;
Pnewnode-> next = NULL;
M_pnodehead = pnewnode;
M_pnodetail = pnewnode;
Nretpos = 1;
Goto exit1;
}
// Is POS range valid?
Assert (1 <= POS & Pos <= m_ncount );
// Insert before head node?
If (1 = POS)
{
Pnewnode-> prior = NULL;
Pnewnode-> next = m_pnodehead;
M_pnodehead-> prior = pnewnode;
M_pnodehead = pnewnode;
Nretpos = 1;
Goto exit1;
}
// If the list is not empty and is not inserted before head node,
// Seek to the POS of the list and insert the new node before it.
Ptmpnode = m_pnodehead;
For (I = 1; I <Pos; ++ I)
{
Ptmpnode = ptmpnode-> next;
}
Pnewnode-> next = ptmpnode;
Pnewnode-> prior = ptmpnode-> prior;
Ptmpnode-> prior-> next = pnewnode;
Ptmpnode-> prior = pnewnode;
// If tail node, must update m_pnodetail
If (null = pnewnode-> next)
{
M_pnodetail = pnewnode;
}
Nretpos = Pos;
Exit1:
++ M_ncount;
Exit0:
Return nretpos;
}
Template <typename T>
Inline int cdlist <t >:: insertafter (const int POs, const t data)
{
Int I;
Int nretpos;
CNode <t> * pnewnode;
CNode <t> * ptmpnode;
Pnewnode = new cNode <t>;
If (null = pnewnode)
{
Nretpos = 0;
Goto exit0;
}
Pnewnode-> DATA = data;
// If the list is empty, replace the head node with the new node.
If (null = m_pnodehead)
{
Pnewnode-> prior = NULL;
Pnewnode-> next = NULL;
M_pnodehead = pnewnode;
M_pnodetail = pnewnode;
Nretpos = 1;
Goto exit1;
}
// Is POS range valid?
Assert (1 <= POS & Pos <= m_ncount );
// If the list is not empty,
// Seek to the POS of the list and insert the new node after it.
Ptmpnode = m_pnodehead;
For (I = 1; I <Pos; ++ I)
{
Ptmpnode = ptmpnode-> next;
}
Pnewnode-> next = ptmpnode-> next;
Pnewnode-> prior = ptmpnode;
// If newnode's position is m_pnodetail, update m_pnodetail
If (ptmpnode-> next = m_pnodetail)
{
M_pnodetail-> prior = pnewnode;
}
Ptmpnode-> next = pnewnode;
// If tail node, must update m_pnodetail
If (null = pnewnode-> next)
{
M_pnodetail = pnewnode;
}
Nretpos = POS + 1;
Exit1:
++ M_ncount;
Exit0:
Return nretpos;
}
Template <typename T>
Inline T & cdlist <t>: getat (const int POS)
{
Assert (1 <= POS & Pos <= m_ncount );
Int I;
CNode <t> * ptmpnode = m_pnodehead;
For (I = 1; I <Pos; ++ I)
{
Ptmpnode = ptmpnode-> next;
}
Return ptmpnode-> data;
}
Template <typename T>
Inline t cdlist <t >:: getat (const int POS) const
{
Assert (1 <= POS & Pos <= m_ncount );
Int I;
CNode <t> * ptmpnode = m_pnodehead;
For (I = 1; I <Pos; ++ I)
{
Ptmpnode = ptmpnode-> next;
}
Return ptmpnode-> data;
}
Template <typename T>
Inline int cdlist <t >:: addhead (const t data)
{
Return insertbefore (1, data );
}
Template <typename T>
Inline int cdlist <t >:: addtail (const t data)
{
Return insertafter (getcount (), data );
}
Template <typename T>
Inline cdlist <t >:: isempty () const
{
Return 0 = m_ncount;
}
Template <typename T>
Inline cdlist <t >:: getcount () const
{
Return m_ncount;
}
Template <typename T>
Inline T & cdlist <t>: gettail ()
{
Assert (0! = M_ncount );
Return m_pnodetail-> data;
}
Template <typename T>
Inline t cdlist <t>: gettail () const
{
Assert (0! = M_ncount );
Return m_pnodetail-> data;
}
Template <typename T>
Inline T & cdlist <t>: gethead ()
{
Assert (0! = M_ncount );
Return m_pnodehead-> data;
}
Template <typename T>
Inline t cdlist <t>: gethead () const
{
Assert (0! = M_ncount );
Return m_pnodehead-> data;
}
Template <typename T>
Inline void cdlist <t>: removeat (const int POS)
{
Assert (1 <= POS & Pos <= m_ncount );
Int I;
CNode <t> * ptmpnode = m_pnodehead;
// Head node?
If (1 = POS)
{
M_pnodehead = m_pnodehead-> next;
Goto exit1;
}
For (I = 1; I <Pos; ++ I)
{
Ptmpnode = ptmpnode-> next;
}
Ptmpnode-> prior-> next = ptmpnode-> next;
Exit1:
Delete ptmpnode;
-- M_ncount;
If (0 = m_ncount)
{
M_pnodetail = NULL;
}
}
Template <typename T>
Inline void cdlist <t>: removehead ()
{
Assert (0! = M_ncount );
Removeat (1 );
}
Template <typename T>
Inline void cdlist <t>: removetail ()
{
Assert (0! = M_ncount );
Removeat (m_ncount );
}
Template <typename T>
Inline void cdlist <t>: removeall ()
{
Int I;
Int ncount;
CNode <t> * ptmpnode;
Ncount = m_ncount;
For (I = 0; I <ncount; ++ I)
{
Ptmpnode = m_pnodehead-> next;
Delete m_pnodehead;
M_pnodehead = ptmpnode;
}
M_ncount = 0;
}
Template <typename T>
Inline void cdlist <t >:: setat (const int POs, t data)
{
Assert (1 <= POS & Pos <= m_ncount );
Int I;
CNode <t> * ptmpnode = m_pnodehead;
For (I = 1; I <Pos; ++ I)
{
Ptmpnode = ptmpnode-> next;
}
Ptmpnode-> DATA = data;
}
Template <typename T>
Inline int cdlist <t>: Find (const t data) const
{
Int I;
Int ncount;
CNode <t> * ptmpnode = m_pnodehead;
Ncount = m_ncount;
For (I = 0; I <ncount; ++ I)
{
If (Data = ptmpnode-> data)
Return I + 1;
Ptmpnode = ptmpnode-> next;
}
Return 0;
}
# Endif/_ double_list_h __
The call is as follows:
//////////////////////////////////////// ///////////////////////////////////////
//
// Filename: Dlist. cpp
// Version 0.10
// Author: Luo Cong
// Date: 2005-1-4 10:58:22
// Comment:
//
//////////////////////////////////////// ///////////////////////////////////////
# Include <iostream>
# Include "Dlist. H"
Using namespace STD;
Int main ()
{
Int I;
Int ncount;
Cdlist <int> Dlist;
# Ifdef _ debug
_ Crtsetdbgflag (_ crtdbg_alloc_mem_df | _ crtdbg_leak_check_df );
# Endif
Dlist. addtail (1 );
Dlist. addtail (3 );
Dlist. insertbefore (2, 2 );
Dlist. addhead (4 );
Dlist. removetail ();
Ncount = Dlist. getcount ();
For (I = 1; I <= ncount ;)
{
Cout <Dlist. getnext (I) <Endl;
}
}
3.2 description
A single-linked table has only one pointer pointing to a direct successor node. Therefore, starting from a node, you can only query other nodes following the pointer. If I want to access the previous node of a certain node, wouldn't I have to start from the header node again? Low Efficiency! In other words, in a single-chain table, the time complexity of getnext () is O (1), while that of getprev () is O (n ). To overcome the unidirectional disadvantage of a single-chain table, we can use -- "Dangdang", only you, is -- double-chain table.
As the name suggests, there are two pointers in the node of the double-stranded table, one pointing to the direct successor, and the other pointing to the direct precursor, which is shown in the C ++ language as follows:
Struct Node
{
Struct node * Prior;
Struct node * next;
T data;
};
Most operations on double-stranded tables (only operations involving pointers in the backward direction) are the same as those on single-stranded tables, but they are quite different in insertion and deletion, you must modify the pointer in both directions in the double-link table. Therefore, you can directly inherit the single-chain table class to complete the double-chain table, and then modify different functions. But I didn't do this. Don't ask why or what the character is.
If you are familiar with the pointer field of a single-chain table, this part of the double-chain table should be difficult for you. Read the code. If there is a bug, please let me know. Pai_^