《数据结构、算法与应用》 C++描述 -- 第6章 线性表 -- 链式描述 学习笔记

线性表 — 链式描述

1. 单向链表

在链式描述中,数据对象实例的每一个元素均用节点来描述,每个节点都明确包含另一个相关节点的位置信息。

单向链表:每个节点只有一个链,从左到右依次连接下一个,最后节点的链域为NULL。

链表的结构定义:

template <class T>
struct chainNode
{
    //数据成员
    T element;  //数据域
    chainNode<T> *next;  //链域
    //方法
    chainNode() {}
    chainNode(const T& element) {
        this->element = element;
    }
    chainNode(const T& element, chainNode<T>* next) {
        this->element = element;
        this->next = next;
    }
};

类chain用单向链表实现线性表

template <class T>
class chain : public linearList<T> {
public:
    chain(int initialCapacity = 10);
    chain(const chain<T>&);
    ~chain();

    //抽象数据类型的方法
    bool empty() const {return listSize == 0;}
    int size() const {return listSize;}
    T& get(int theIndex) const;
    int indexOf(const T& theElement) const;
    void erase(int theIndex);
    void insert(int theIndex, const T& theElement);
    void output(ostream& out) const;
private:
    void chackIndex(int theIndex) const;
    chainNode<T>* firstNode;  //指向首元素
    int listSize;  //元素个数
};

构造函数和拷贝构造函数:

template <class T>
chain<T>::chain(int initialCapacity) {
    if (initialCapacity < 1) {
        ostringstream s;
        s << "Initial capacity must be > 0!";
        throw illwgalParameterValue(s.str());
    }
    firstNode = NULL;
    listSize = 0;
}

//拷贝构造函数
template <class T>
chain<T>::chain(const chain<T>& theList) {
    listSize = theList.listSize;
    if (listSize == 0) {
        firstNode = NULL;
        return;
    }
    chainNode<T>* sourceNode = theList.firstNode;
    firstNode = new chainNode<T>(sourceNode->element);
    sourceNode = sourceNode->next;
    chainNode<T>* targetNode = firstNode;
    while (sourceNode != nullptr) {
        targetNode->next = new chainNode<T>(sourceNode->element);
        targetNode = targetNode->next;
        sourceNode->next = sourceNode->next;
    }
    targetNode->next = nullptr;
}

析构函数:

析构函数要逐个清除链表的节点,实现方法是:重复清除链表的首个元素,直到链表为空。

//析构函数
template <class T>
chain<T>::~chain() {
    while (firstNode != nullptr) {
        chainNode<T>* nextNode = firstNode->next;
        delete firstNode;
        firstNode = nextNode;
    }
}

get():返回索引为Index的元素。

template <class T>
T& chain<T>::get(int index) const {
    checkIndex(index);
    chainNode<T>* curNode = firstNode;
    for (int i = 0; i < index; i++) {
        curNode = firstNode->next;
    }
    return curNode->element;
}

indexOf(): 返回元素element首次出现的索引

template <class T>
int chain<T>::indexOf(const T& elememt) const {
    chainNode<T>* curNode = firstNode;
    index = 0;
    while (curNode != nullptr && curNode->element != elememt) {
        curNode = curNode->next;
        index++;
    }
    if (curNode == nullptr) {
        return -1;
    } else {
        return index;
    }
}

erase():删除索引为index的元素。

可能有三种情况:

  • index不合法
  • index= 0,即删除首元素
  • 删除其他元素。
template <class T>
void chain<T>::erase(int index) {
    chackIndex(index);
    chainNode<T>* delNode;
    if (index == 0) {
        delNode = firstNode;
        firstNode = firstNode->next;
    } else {
        chainNode<T>* curNode = firstNode;
        for (int i = 0; i < index - 1; i++) { //注意是index - 1
            curNode = curNode->next;
        }
        delNode = curNode->next;
        curNode->next = curNode->next->next;
    }
    listSize--;
    delete delNode;
}

index(): 需要先找到索引为index - 1 的节点,然后在该节点后插入。

template <class T>
void chain<T>::insert(int index, const T& val) {
    chackIndex(index);
    if (index = 0) {
        firstNode = new chainNode<T>(val, firstNode);
    } else {
        chainNode<T>* curNode = firstNode;
        for (int i = 0; i < index - 1; i++) {
            curNode = curNode->next;
        }
        curNode->next = new chainNode<T>(val, curNode->next);
    }
    listSize++;
}

输出:

template <class T>
void chain<T>::output(ostream & out) const {
    for (chainNode<T>* curNode = firstNode; curNode != nullptr; curNode = curNode->next) {
        out << curNode->element << " ";
    }
}
//重载<<
template <class T>
ostream& operator<<(ostream& out, const chain<T>& x) {
    x.output(out);
    return out;
}

2. 迭代器

class iterator 
{
   public:
      iterator(chainNode<T>* theNode = NULL)
         {node = theNode;}

      T& operator*() const {return node->element;}
      T* operator->() const {return &node->element;}

      iterator& operator++()   // preincrement
                {node = node->next; return *this;}
      iterator operator++(int) // postincrement
      	      {iterator old = *this;
      	       node = node->next;
      	       return old;
      	      }

      bool operator!=(const iterator right) const
            {return node != right.node;}
      bool operator==(const iterator right) const
            {return node == right.node;}
   protected:
      chainNode<T>* node;
};  

begin() and end()

class iterator;
iterator begin() {return iterator(firstNode);}
iterator end() {return iterator(NULL);}

clear() and push_back()

template<class T>
class extendedLinearList : linearList<T>
{
public:
	virtual ~extendedLinearList() {};
	virtual void clear() = 0;
	virtual void push_back(const T& element) = 0;
};

//clear() 实现
template<class T>
inline void extendedChain<T>::clear()
{
	this->listSize = 0;
	while (this->first != nullptr)
	{
		auto next = this->first->next;
		delete this->first;
		this->first = next;
	}
}

//push_back() 实现
template<class T>
void extendedChain<T>::push_back(const T& theElement)
{// Insert theElement at the end of the chain.
   chainNode<T>* newNode = new chainNode<T>(theElement, NULL);
   if (firstNode == NULL)
      // chain is empty
      firstNode = lastNode = newNode;
   else
   {  // attach next to lastNode
      lastNode->next = newNode;
      lastNode = newNode;
   }
   listSize++;
}

3. 循环链表和头结点

循环链表:在链表前边加一个头结点,然后将单向链表的尾结点和头结点相连,即可构成循环链表。使用头结点可使程序更简洁和素的更快。

template<class T>
class circularListWithHeader 
{
   public:
      circularListWithHeader();

      // some methods
      int size() const {return listSize;}
      int indexOf(const T& theElement) const;
      void insert(int theIndex, const T& theElement);
      void output(ostream& out) const;

   protected:
      void checkIndex(int theIndex) const;
            // throw illegalIndex if theIndex invalid
      chainNode<T>* headerNode;  // pointer to header node
      int listSize;              // number of elements in list
};

template<class T>
circularListWithHeader<T>::circularListWithHeader()
{// Constructor.
   headerNode = new chainNode<T>();
   headerNode->next = headerNode;
   listSize = 0;
}

template<class T>
int circularListWithHeader<T>::indexOf(const T& theElement) const
{
   headerNode->element = theElement;

   // search the chain for theElement
   chainNode<T>* currentNode = headerNode->next;
   int index = 0;  // index of currentNode
   while (currentNode->element != theElement)
   {
      // move to next node
      currentNode = currentNode->next;
      index++;
   }

   // make sure we found matching element
   if (currentNode == headerNode)
      return -1;
   else
      return index;
}

双向链表

双向链表支持双向访问,每个节点都包含两个指针(next 和 previous),以此来决定向右查找还是向左查找。

源码见GitHub:线性表–链式描述源码

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值