和数组不同,链表的数据结构内部多了一个指针指针下一个位置,使得在链表中插入删除特定位置的元素效率很高,代码实现依旧分为三个部分,抽象类LinearList.h,模板类chain.h以及main函数源文件。
废话不多说,我们看代码,这次LinearList.h抽象类里面多了两个成员函数一个是push_back(),一个是clear():
//
// Created by djf on 2016/12/18 0018.
//
#ifndef INC_01_ARRAYLIST_LINEARLIST_H
#define INC_01_ARRAYLIST_LINEARLIST_H
#include
template
class LinearList {
public:
virtual ~LinearList() {};
virtual bool empty() const = 0;
virtual int size() const = 0;
virtual T& get(int index) const = 0;
virtual int indexof(const T& theElement) const = 0;//first pos
virtual void erase(int index) = 0;
virtual void insert(int index, const T& theElement) = 0;
virtual void output(std::ostream& out) const = 0;
//extend
virtual void clear() = 0;
virtual void push_back(const T& theElement) = 0;
};
#endif //INC_01_ARRAYLIST_LINEARLIST_H
//
// Created by djf on 2016/12/20 0020.
//
#ifndef INC_02_CHAIN_CHAIN_H
#define INC_02_CHAIN_CHAIN_H
#include "LinearList.h"
using namespace std;
template
struct chainNode{
//data
T element;
chainNode
*next;
//method
chainNode() {}
chainNode(const T& e) { this->element=e;}
chainNode(const T& e, chainNode
* n) { this->element=e;this->next=n;}
};
template
class chain: public LinearList
{ public: //one direction iterator class iterator{ public: // typedefs required by C++ for a forward iterator typedef forward_iterator_tag iterator_category; typedef T value_type; typedef ptrdiff_t difference_type; typedef T* pointer; typedef T& reference; //construct iterator(chainNode
* theNode = nullptr) { node = theNode;} //operator T& operator*() const { return node->element;} T* operator&() const { return &node->element;} iterator& operator++() { node = node->next;return *this;} iterator operator++(int) { iterator old = *this; node = node->next; return old;} bool operator==(const iterator rhl) const { return node == rhl.node;} bool operator!=(const iterator rhl) const { return node != rhl.node;} //other protected: chainNode
* node; }; public: //consturct copy destory chain(int initCapacity=10); chain(const chain
&); ~chain(); //ADT method from LinearList.h bool empty() const override { return listSize==0;}; int size() const override { return listSize;} T& get(int index) const override; int indexof(const T&) const override; void erase(int index) override; void insert(int index,const T& theElement) override; void output(ostream& out) const override; void push_back(const T& theElement) override ; void clear() override ; //other void removeRange(int fromIndex,int toIndex); int lastIndexOf(const T& theElement); T& operator[](int index) const; void reverse(); protected: void checkIndex(int index) const; chainNode
* headNode; int listSize; }; template
void chain
::removeRange(int fromIndex, int toIndex) { checkIndex(fromIndex);checkIndex(toIndex); if(toIndex
* p = headNode; if(fromIndex!=0) { chainNode
* q; for(int i = 0;i
next; else { q = p->next; p->next = q->next; delete q; } } } else { for(int i = 0;i<=toIndex;++i) { headNode = headNode->next; delete p; p = headNode; } } } template
chain
::chain(int initCapacity) { //chain中无capacity,这么写为了和LinearList兼容 if(initCapacity<1) cerr << "----!initSize must be >=1 !----"; listSize = 0; headNode = nullptr; } template
chain
::chain(const chain
& theList) { listSize = theList.listSize; if(listSize==0) { headNode = nullptr; return; } chainNode
* sourceNode = theList.headNode; headNode = new chainNode
(sourceNode->element); sourceNode = sourceNode->next; chainNode
* targetNode = headNode; while(sourceNode!= nullptr) { targetNode->next = new chainNode
(sourceNode->element); sourceNode = sourceNode->next; targetNode = targetNode->next; } targetNode->next = nullptr; } template
chain
::~chain() { wsnippet_file_0hile(headNode!= nullptr) { chainNode
* nextNode = headNode->next; delete headNode; headNode = nextNode; } } template
T &chain
::get(int index) const { checkIndex(index); chainNode
* currNode = headNode; for(int i=0;i
next; return currNode->element; } template
void chain
::checkIndex(int index) const { if(index<0 || index>=listSize) { cerr << "----! index outrange !----" << endl; return; } } template
int chain
::indexof(const T & theElement) const { chainNode
* currNode = headNode; for(int i = 0;i
element==theElement) return i; currNode = currNode->next; } return -1; } template
void chain
::erase(int index) { checkIndex(index); chainNode
* deleteNode; if(index==0) { deleteNode = headNode; headNode = headNode->next; } else { chainNode
*p = headNode; for(int i=0;i
next; deleteNode = p->next; p->next = p->next->next; } --listSize; delete deleteNode; } template
void chain
::insert(int index, const T &theElement) { if(index<0 || index>listSize) { cerr << "---! insert index error !----" << endl; return; } if(index ==0) { headNode = new chainNode
(theElement,headNode); } else { chainNode
*p = headNode; for (int i = 0; i < index - 1; ++i) p = p->next; p->next = new chainNode
(theElement, p->next); } listSize++; } template
void chain
::output(ostream &out) const { for(chainNode
* p = headNode;p != nullptr;p=p->next) out << p->element << " "; } template
void chain
::push_back(const T &theElement) { chainNode
* currNode = headNode; for(int i=0;i
next; currNode->next = new chainNode
(theElement, nullptr); ++listSize; } template
void chain
::clear() { chainNode
* p; while(headNode!= nullptr) { p = headNode->next; delete headNode; headNode = p; } listSize = 0; } template
int chain
::lastIndexOf(const T& theElement) { int pos = -1;int i = 0; chainNode
* p = headNode; while (p != nullptr) { if (p->element == theElement) pos = i; else { ++i; p = p->next; } } } template
T& chain
::operator[](int index) const { checkIndex(index); chainNode
* currNode = headNode; for(int i = 0;i
next; return currNode->element; } template
void chain
::reverse() { if(listSize==0 || listSize==1) return; else if(listSize == 2) { chainNode
* p = headNode; headNode = headNode->next; headNode->next = p; p->next = nullptr; } else { chainNode
* p = headNode; chainNode
* q = headNode->next; chainNode
* r = headNode->next->next; headNode->next = nullptr; while(r->next != nullptr) { q->next = p; p = q; q = r; r = r->next; } q->next = p; r->next = q; headNode = r; } } template
ostream& operator<<(ostream& out, const chain
&a) { a.output(out); return out; } #endif //INC_02_CHAIN_CHAIN_H
#include <iostream>
#include "chain.h"
int main()
{
chain<int> ic;
ic.insert(0,1);ic.insert(0,2);ic.push_back(3);ic.push_back(4);
chain<int> ic1(ic);ic1.reverse();
cout << ic1 << endl;
return 0;
}
我发现写这个还是很锻炼人的,一个完善的数据结构轻轻松松几百行代码,每天一发,感觉很酸爽,C++简直写上瘾。
不废话了,我们回归头来看看链表的头文件里都定义了啥:
chainNode类定义了节点类,包含数据成员以及指向下一个节点的指针。包含构造、拷贝以及析构函数。
chan类继承自LinearList抽象类,包含节点类的成员变量,以及一个嵌套类iterator。
成员函数分为几个部分,首先是构造、拷贝以及析构函数,值得注意的是在构造函数中有一个参数initCapacity,实际是无作用的,仅仅为了和之前的ArrayList一致。
然后是继承自抽象类的方法,和ArrayList中的区别不大。
最后是我做的几个习题,void removeRange(int fromIndex,int toIndex)的作用是将参数限定范围内的节点删除的操作。int lastIndexOf(const T& theElement)是返回与函数参数相等的最后一个位置的索引。T& operator[](int index) const 是对[]运算符进行重载,返回指定索引的节点的数据的引用。void reverse()是将整个链表进行反转的操作,要求不开辟多余的空间。