วันจันทร์ที่ 8 พฤศจิกายน พ.ศ. 2553

linklist - implementing doubly linked list with template

///////////////////////////////////////////////////////////////////////////////
// linklist.h
// Author: Seree Rakwong
// Date: 8-NOV-10
// Purpose: Link list container
#ifndef linklist_h
#define linklist_h

namespace mstd {

template<class T>
class linklist {
public:
  class linklist_node {
    T data_;
    linklist_node *prev_;
    linklist_node *next_;
  public:
    linklist_node(const T& data)
      : data_(data),
        prev_(0),
        next_(0)
    {}
  public:
                T   data() const { return data_; }
               T&   data()       { return data_; }
    linklist_node  *prev() const { return prev_; }
    linklist_node *&prev()       { return prev_; }
    linklist_node  *next() const { return next_; }
    linklist_node *&next()       { return next_; }
  }; // class linklist_node

private:
  linklist_node *begin_;
  linklist_node *end_;
  unsigned long  count_;
  
public:
  linklist()
    : begin_(0),
      end_(0),
      count_(0)
  {}
  virtual ~linklist() { remove_all(); }

public:
  linklist_node  *begin() const { return begin_; }
  linklist_node *&begin()       { return begin_; }
  linklist_node  *end()   const { return end_;   }
  linklist_node *&end()         { return end_;   }
  unsigned long   count() const { return count_; }
public:
  // remove all nodes
  void remove_all() {
    linklist_node *del_node = begin_;
    while(del_node) {
      begin_ = begin_->next();
      delete del_node;
      del_node = 0;        // safe to use in the future
      del_node = begin_;
    }
    begin_ = 0;
    end_  = 0;
    count_ = 0;
  }
  // remove the first
  void remove_begin() {
    if(!begin_) return; // don't do anything
    
    linklist_node *node = begin_;
    begin_ = begin_->next();
    begin_->prev() = 0;
    delete node;
    node = 0;
    
    count_--;
  }
  // remove the last
  void remove_end() {
    if(!end_) return; // don't do anything
    
    linklist_node *node = end_;
    end_ = end_->prev();
    end_->next() = 0;
    delete node;
    node = 0;
    
    count_--;
  }
  // remove at the node
  void remove_at(linklist_node *at) {
    if(!at) return// don't do anything
    
    linklist_node *next = at->next();
    linklist_node *prev = at->prev();
    
    next->prev() = prev;
    prev->next() = next;
    
    delete at;
    at = 0;   // safe to use in the future
  }
  // insert a new node at the first
  linklist_node *insert_begin(const T& data) {
    linklist_node *node = new linklist_node(data);
    if(!node) return 0;
    
    if(!begin_) {
      begin_ = node;
      end_   = node;
    }
    else {
      node->next()   = begin_;
      begin_->prev() = node;
      begin_         = node;
    }
    count_++;
    return node;
  }
  // insert a new node at the last
  linklist_node *insert_end(const T& data) {
    linklist_node *node = new linklist_node(data);
    if(!node) return 0;
    
    if(!begin_) {
      begin_ = node;
      end_   = node;
    }
    else {
      node->prev() = end_;
      end_->next() = node;
      end_         = node;
    }
    count_++;
    return node;
  }
  // insert a new node before the node
  linklist_node *insert_before(const T& data, linklist_node *at) {
    if(!at) return 0;
    
    linklist_node *node = new linklist_node(data);
    if(!node) return 0;
    
    // link to
    //linklist_node *next = at->next();
    linklist_node *prev = at->prev();
    node->next() = at;
    at->prev()   = node;
    node->prev() = prev;
    if(prev) prev->next() = node;
    
    count_++;
    return node;
  }
  // insert a new node after the node
  linklist_node *insert_after(const T& data, linklist_node *at) {
    if(!at) return 0;
    
    linklist_node *node = new linklist_node(data);
    if(!node) return 0;
    
    // link to
    linklist_node *next = at->next();
    node->prev() = at;
    at->next()   = node;
    node->next() = next;
    if(next) next->prev() = node;
    
    count_++;
    return node;
  }
  // insert a new node by reverse sorting
  linklist_node *insert_rsort(const T& data) {
    linklist_node *node = new linklist_node(data);
    if(!node) return 0;
    
    if(!begin_) {
      begin_ = node;
      end_   = node;
    }
    else {
      linklist_node *current = end_;
      while(current) {
        if(data <= current->data()) {
          if(current == end_) {
            node->prev() = end_;
            end_->next() = node;
            end_         = node;
          }
          else {
            node->prev()    = current;
            node->next()    = current->next();
            if(current->next()) current->next()->prev() = node;
            current->next() = node;
          }
          break;
        }
        current = current->prev();
      }
      // its value is less than the first
      if(!current) {
        node->next()   = begin_;
        begin_->prev() = node;
        begin_         = node;
      }
    }
    count_++;
    return node;
  }
  // insert a new node by sorting
  linklist_node *insert_sort(const T& data) {
    linklist_node *node = new linklist_node(data);
    if(!node) return 0;
    
    if(!begin_) {
      begin_ = node;
      end_   = node;
    }
    else {
      linklist_node *current = begin_;
      while(current) {
        if(data <= current->data()) {
          if(current == begin_) {
            node->next()   = begin_;
            begin_->prev() = node;
            begin_         = node;
          }
          else {
            node->next()    = current;
            node->prev()    = current->prev();
            if(current->prev()) current->prev()->next() = node;
            current->prev() = node;
          }
          break;
        }
        current = current->next();
      }
      // its value is greater than the last
      if(!current) {
        node->prev() = end_;
        end_->next() = node;
        end_         = node;
      }
    }
    count_++;
    return node;
  }
  // find the node
  linklist_node *find(const T& data, linklist_node *at = 0) {
    if(!at) at = begin_;
    if(!at) return 0; // no node to be searched
    
    while(at) {
      if(at->data() == data) {
        return at;
      }
      at = at->next();
    }
    return 0;
  }
  // reverse find the node
  linklist_node *reverse_find(const T& data, linklist_node *at = 0) {
    if(!at) at = end_;
    if(!at) return 0; // no node to be searched
    
    while(at) {
      if(at->data() == data) {
        return at;
      }
      at = at->prev();
    }
    return 0;
  }
  // swap between a node and a node
  int swap(linklist_node *first, linklist_node *second) {
    if(!first || !second) return 1; // cannot swap

    T temp = first->data();
    first->data()  = second->data();
    second->data() = temp;
    return 0;
  }
  // find the middle of two nodes
  linklist_node *mid(linklist_node *first, linklist_node *last) {
    linklist_node *m = first;
    unsigned long count = 1;
    while(m && m != last) {
      m = m->next();
      count++;
    }
    // get the middle node
    m = first;
    for(unsigned long l = 0; l < count/2; l++) {
      m = m->next();
    }
    return m;
  }
  unsigned long pos(linklist_node *at) {
    if(!at || !begin_) return 0; // no node
    
    linklist_node *current = begin_;
    unsigned long count = 1;
    while(current) {
      if(current == at) {
        return count;
      }
      count++;
      current = current->next();
    }
    return 0; // not found
  }
  unsigned long reverse_pos(linklist_node *at) {
    if(!at || !end_) return 0; // no node
    
    linklist_node *current = end_;
    unsigned long count = count_;
    while(current) {
      if(current == at) {
        return count;
      }
      count--;
      current = current->prev();
    }
    return 0; // not found
  }
}; // class linklist


}; // namespace mstd

#endif //linklist_h

///////////////////////////////////////////////////////////////////////////////
// test.cpp
// Author: Seree Rakwong
// Date: 8-NOV-10
// Purpose: Link list container
#include "linklist.h"
#include <iostream>

using namespace mstd;
using namespace std;

int main() {
  linklist<int> list;
  linklist<int>::linklist_node *node = list.insert_begin(30);
  list.insert_rsort(50);
  list.insert_rsort(40);
  list.insert_rsort(20);
  list.insert_rsort(10);
  list.insert_rsort(60);

  cout << "list all nodes..." << endl;
  linklist<int>::linklist_node *current = list.begin();
  while(current) {
    cout << current->data() << endl;
    current = current->next();
  }
  cout << "reverse find(50): ";
  current = list.reverse_find(50);
  if(current) cout << "found" << endl;
  else cout << "not found" << endl;
  
  cout << "list nodes left..." << endl;
  list.remove_begin();
  list.remove_end();
  list.remove_at(node);
  current = list.begin();
  while(current) {
    cout << current->data() << endl;
    current = current->next();
  }
  
  cout << "find(50): ";
  current = list.find(50);
  if(current) cout << "found" << endl;
  else cout << "not found" << endl;
  
  list.swap(list.begin(), list.end());
  current = list.begin();
  while(current) {
    cout << current->data() << endl;
    current = current->next();
  }
  
  return 0;
}