使用单指针实现双链表(C++语言)

来源:互联网 发布:淘宝怎么开通电子面单 编辑:程序博客网 时间:2024/06/03 16:54

本文是Clifford A. Shaffer所著《数据结构与算法分析》(C++版)习题4.4的解答。

链表是常见的数据结构,链表中的结点通常定义如下。

template <typename E> class Link {public:  E element;  Link<E> *next;  Link(const E& it, Link<E>* next) { }};

结点是一个定义为Link的模板类,其元素element的类型E可以代入不同的具体类型,指针成员nex指向下一个结点。只有一个指针的结点只能用于单链表,在使用时需要保存一个头指针head,搜索链表的时候,每次都要从head开始,而且只能向后搜索,不能向前搜索。

双链表中的结点含有两个指针域,分别为prev和next,如下所示。

template <typename E> class Link {public:  E element;  Link<E> *prev, *next;  Link(const E& it, Link<E>* prev, Link<E>* next) { }};
双链表在使用时可以保存一个头指针head,一个尾指针next。既可以从head出发向后搜索,也可以从tail出发向前搜索。如果再增加一个当前指针curr,那么在单链表中,只能从curr出发向后搜索,而在双链表中,可以从curr出发向后或者向前搜索。

基于结点类,可以设计链表类,下面的抽象数据类型给出了链表类所需要支持的基本操作。

template <typename E> class List { // List ADTprivate:  void operator =(const List&) {}   List(const List&) {} public:  List() {}  virtual ~List() {}  virtual void clear() = 0;  virtual void insert(const E& item) = 0;  virtual void append(const E& item) = 0;  virtual E remove() = 0;  virtual void moveToStart() = 0;  virtual void moveToEnd() = 0;  virtual void prev() = 0;  virtual void next() = 0;  virtual int length() const = 0;  virtual int currPos() = 0;  virtual void moveToPos(int pos) = 0;  virtual const E& getValue() const = 0;};
基于带有prev和next指针的结点类Link来说,通过在链表中增加head、tail或者curr成员变量,很容易写出一个双向链表的实现,支持上述抽象类List中的操作。但是,也可以在Link类中只使用一个指针pt,而实现双向链表。主要思想是从这一个指针中,既可以获取prev的内容,也可以获取next的内容。其实现依赖于异或操作的一个重要性质:

(L^R)^R = L, (L^R)^L = R。

可以定义指针pt的值为

pt = prev ^ next。

也就是说,pt是其后向指针next和前向指针prev的异或。那么,当前结点的pt和指向其之前结点的指针在做异或操作,就可以得到指向当前结点之后的结点的指针。当前结点的pt和指向其之后结点的指针做异或操作,就可以得到指向当前结点之前的结点的指针。换言之,在这种形式的双链表中,除了保存head,tail和curr指针指向链表中的不同结点之外,还需要使用两个指针prevp和nextp,分别指向curr结点之前和之后的结点。从当前结点向后移动一步时,可以通过如下语句序列实现。

prevp = curr;curr = nextp;nextp = prevp ^ curr->pt;
从当前结点向前一步所对应的语句序列如下。

nextp = curr;curr = prevp;prevp = curr->pt  ^ nextp;

当然,链表中多了两个变量prevp和nextp,但是每个结点都节省了一个指针,所以总体而言,这种双链表的实现能够大幅度节省空间。当然这是以搜索时计算步骤增多、时间变长为代价的。

双向链表的具体实现代码如下。

template <typename E> class LList: public List<E> {private:  Link<E>* head, *tail, *curr;  Link<E> *prevp, *nextp;   int cnt;  void init() {    curr = head = new Link<E>;    head->pt = tail = new Link<E>(head, NULL);    prevp = NULL;    nextp = tail;    cnt = 0;  }  void removeall() {    prevp = NULL;    while(head != NULL) {      curr = head;      head = xor_op(prevp, head->pt);      prevp = curr;      delete curr;    }  }  Link<E>* xor_op(Link<E>* pt1, Link<E>* pt2)  {    unsigned long op1 = (unsigned long)pt1;    unsigned long op2 = (unsigned long)pt2;    return (Link<E>*)(op1 xor op2);  }public:  LList(int size=defaultSize) { init(); }  ~LList() { removeall(); }   void clear() { removeall(); init(); }   void moveToStart() // Place curr at list start  {    curr = head;    prevp = NULL;    nextp = head->pt;  }  void moveToEnd()   // Place curr at list end  {    curr = tail->pt;    nextp = tail;    prevp = xor_op(tail, curr->pt);  }    void next()  {    if (curr != tail->pt)    {      prevp = curr;      curr = nextp;      nextp = xor_op(prevp, curr->pt);    }  }  int length() const  { return cnt; }  // Return the position of the current element  int currPos() {    Link<E>* temp = head;    int i;    prevp = NULL;    nextp = head->pt;    for (i=0; curr != temp; i++){      prevp = temp;      temp = nextp;      nextp = xor_op(prevp, temp->pt);    }    return i;  }  // Move down list to "pos" position  void moveToPos(int pos) {    Assert ((pos>=0)&&(pos<=cnt), "Position out of range");    curr = head;    prevp = NULL;    nextp = head->pt;    for(int i=0; i<pos; i++)    {      prevp = curr;      curr = nextp;      nextp = xor_op(prevp, curr->pt);    }  }  const E& getValue() const { // Return current element    if(nextp == tail)      return NULL;    return nextp->element;  }  void insert(const E& it) {    Link<E> *tmp;    tmp = new Link<E>(it, curr, nextp);    curr->pt = xor_op(xor_op(curr->pt, nextp), tmp);    nextp->pt = xor_op(xor_op(nextp->pt, curr), tmp);    nextp = tmp;    cnt++;  }  void append(const E& it) {    Link<E> *tmp;    tmp = new Link<E>(it, tail->pt, tail);    tail->pt->pt = xor_op(xor_op(tail->pt->pt, tail), tmp);    tail->pt = tmp;    if(nextp == tail)      nextp = tmp;    cnt++;  }  E remove() {    if(nextp == tail)      return NULL;    Link<E> *new_next;    E it = nextp->element;    new_next = xor_op(nextp->pt, curr);    curr->pt = xor_op(prevp, new_next);    new_next->pt = xor_op(xor_op(nextp, new_next->pt), curr);    delete nextp;    nextp = new_next;    cnt--;    return it;  }  void prev()  {    if (curr != head)    {      nextp = curr;      curr = prevp;      prevp = xor_op(nextp, curr->pt);    }  }}; 













0 0
原创粉丝点击