1、双向链表的实现
交流中。。。
单链表的另—个缺陷
-单向性
只能从头结点开始高效访问链表中的数据元素
-缺陷
如果需要 逆向访问单链表中的数据元素将 极其低效
新的线性表
设计思路:
在“单链表”的结点中增加指针pre,
用于指向当前结点的前驱结点。
双向链表的继承层次结构
在有些设计方案中是作为LinList的子类实现的
DualLinkList的定义
2、编程实验
双向链表的实现 DualLinkList.h
注意3、4操作的条件
DualLinkList.h
- #ifndef DUALLINKLIST_H
- #define DUALLINKLIST_H
- #include"List.h"
- #include"Exception.h"
- namespace DTLib
- {
- template <typename T>
- class DualLinkList : public List<T>
- {
- protected:
- struct Node : public Object
- {
- T value;
- Node* next;
- Node* pre;
- };
- mutable struct : public Object
- {
- char reserved[sizeof(T)];
- Node* next;
- Node* pre;
- }m_header;
- int m_length;
- Node* m_current;
- int m_step;
- Node* position(int i) const
- {
- Node* ret = reinterpret_cast<Node*>(&m_header);
- for(int p=0;p<i;p++)
- {
- ret = ret->next;
- }
- return ret;
- }
- virtual Node* create()
- {
- return new Node();
- }
- virtual void destroy(Node* pn)
- {
- delete pn;
- }
- public:
- DualLinkList()
- {
- m_header.next = NULL;
- m_header.pre = NULL;
- m_length = 0;
- m_step = 1;
- m_current = NULL;
- }
- bool insert(int i,const T& e)
- {
- bool ret = (0 <= i)&&(i <= m_length);
- if(ret)
- {
- Node* node = create();
- if( node )
- {
- Node* current = position(i);
- Node* next = current->next;
- node->value = e;
- node->next = next;
- current->next = node;
- if( current != reinterpret_cast<Node*>(&m_header) )
- {
- node->pre = current;
- }
- else
- {
- node->pre = NULL;
- }
- if(next != NULL) //新结点插入最后位置
- {
- next->pre = node;
- }
- m_length++;
- }
- else
- {
- THROW_EXCEPTION(NoEnoughMemoryException,"No memory to insert new element ...");
- }
- }
- return ret;
- }
- bool insert(const T& e)
- {
- return insert(m_length,e);
- }
- bool remove(int i)
- {
- bool ret = (0 <= i)&&(i < m_length);
- if(ret)
- {
- Node* current = position(i);
- Node* toDel = current->next;
- Node* next = toDel->next;
- if(m_current == toDel)
- {
- m_current = next; //游标指向下一个数据元素即可
- }
- current->next = next;
- if(next != NULL)
- next->pre = toDel->pre;
- m_length--;
- destroy(toDel);
- }
- return ret;
- }
- bool set(int i,const T& e)
- {
- bool ret = (0 <= i)&&(i < m_length);
- if(ret)
- {
- position(i)->next->value = e;
- }
- return ret;
- }
- virtual T get(int i) const
- {
- T ret;
- if(get(i,ret))
- {
- return ret;
- }
- else
- {
- THROW_EXCEPTION(IndexOutOfBoundsExpception,"Invalid parameter i to get element ...");
- }
- return ret;
- }
- bool get(int i,T& e) const
- {
- bool ret = (0 <= i)&&(i < m_length);
- if(ret)
- {
- e = position(i)->next->value; //position 为 const 成员函数
- }
- return ret;
- }
- int find(const T& e) const
- {
- int ret = -1;
- int i = 0;
- Node* node = m_header.next;
- while( node )
- {
- if(node->value == e)
- {
- ret = i;
- break;
- }
- else
- {
- node = node->next;
- i++;
- }
- }
- return ret;
- }
- int length() const
- {
- return m_length;
- }
- void clear() //O(n)
- {
- while(m_length > 0)
- {
- remove(0);
- }
- }
- virtual bool move(int i,int step = 1)
- {
- bool ret = (0 <= i)&&(i < m_length)&&(step > 0);
- if(ret)
- {
- m_current = position(i)->next;
- m_step = step;
- }
- return ret;
- }
- virtual bool end()
- {
- return ( m_current == NULL);
- }
- virtual T current()
- {
- if(!end())
- {
- return m_current->value;
- }
- else
- {
- THROW_EXCEPTION(InvalidParameterException,"No value at current position ...");
- }
- }
- virtual bool next()
- {
- int i = 0;
- while((i < m_step) && !end())
- {
- m_current = m_current->next;
- i++;
- }
- return (i == m_step);
- }
- virtual bool pre()
- {
- int i = 0;
- while((i < m_step) && !end())
- {
- m_current = m_current->pre;
- i++;
- }
- return (i == m_step);
- }
- ~DualLinkList()
- {
- clear();
- }
- };
- }
- #endif // DUALLINKLIST_H
main.cpp
#include <iostream>
#include"DualLinkList.h"
using namespace std;
using namespace DTLib;
int main()
{
DualLinkList<int> d1;
for(int i=0;i<5;i++)
{
d1.insert(0,i);
d1.insert(0,5);
}
for(d1.move(0);!d1.end();d1.next())
{
cout<<d1.current()<<" ";
}
cout<<endl;
for(d1.move(d1.length()-1);!d1.end();d1.pre()) //逆序访问 O(1)
{
cout<<d1.current()<<" ";
}
cout<<endl;
d1.move(d1.length()-1);
while(!d1.end())
{
if(d1.current() == 5)
{
cout<<d1.current()<<" ";
d1.remove(d1.find(d1.current()));
}
else
{
d1.pre();
}
}
cout<<endl;
for(d1.move(d1.length()-1);!d1.end();d1.pre())
{
cout<<d1.current()<<" ";
}
cout<<endl;
return 0;
}
3、小结
双向链表是为了弥补单链表的缺陷而重新设计的
在概念上,双向链表不是单链表,没有继承关系
双向链表中的游标能够直接访问当前结点的前驱和后继
双向链表是线性表概念的最终实现( 更贴近理论上的线性表 )4、深度思考
开放性问题
DualLinkList和LinkList中存在很多完全—样的代
码,如何进行重构降低代码的冗余性?冗余代码的
出现是否意味着DualLinkList和LinkList之间应该
是继承关系?
5、扩展练习
双向链表的子类