线性表list,有元素组成的有限且有序的序列。
线性表有两种:顺序表(array-based list或sequencetial list)和链表(Linked list)
“栅栏”思维。
下面把right/left partition简称right/left。注意理解“位置”pos:
left partition的大小一直是等于fence的pos。
ADT
//最基本(抽象)的线性表的C++抽象结构template <class Elem> class List{public:virtual void clear() = 0;//清空表virtual bool insert(const Elem&) = 0; //right的前面插入virtual bool append(const Elem&) = 0; //right的最后面插入virtual bool remove(Elem& elem) = 0; /删除right的第一个,注意不是删除elem相同的元素virtual void setStart() = 0; //fence在最前面,left为空的时候virtual void setEnd() = 0; //fence在最后面,rihgt为空的时候virtual void prev() = 0; //fence往左移动一个,left大小-1virtual void next() = 0; //fence往右移动一个,right大小-1virtual int leftLength() const = 0; //left的大小virtual int rightLength() const = 0; //right的大小virtual bool setPos(int pos) = 0; //设置fence使leftLength() = posvirtual bool getValue(Elem&) const = 0; //返回right的第一个elem,没有bool=falsevirtual void print() const = 0; //打印表全部元素//此方法非最基础抽象,可加可不加bool find(List<int>& L, int K){int t;for(L.setStart();L.getValue(t);L.next())if(t == K) return true;return false;}}
1、顺序表AList(UAList)
也是一个无序的顺序表,Unsorted Array List。又是有序又是无序的怎么理解:
一群年龄大小不一的人坐在一排凳子上。
无序:这群人没有按年龄排序坐。
顺序表:他们做在一排凳子上,互相紧挨着。
链表结构C++实现
template<class Elem>class AList: public List<Elem>{private:int32_t maxSize;int32_t listSize;int32_t fence;Elem* listArray;public:AList(int size = DefaultListSize){maxSize = size;listSize = fence = 0;listArray = new Elem[maxSize];}~AList(){delete[] listArray;}//以下全部是线性表List的成员方法。virtual void clear(){listSize = fence = 0;delete[] listArray;listArray = new Elem[maxSize];}virtual bool insert(const Elem& elem){if(listSize == maxSize) return false;for(int32_t i = listSize; i > fence; i++)listArray[i] = listArray[i - 1];listArray[fence] = elem;listSize++;return true;}virtual bool append(const Elem& elem){if(listSize == maxSize) return false;listArray[listSize++] = elem;return true;}virtual bool remove(Elem& elem){if(rightLenghth() == 0) return false;elem = listArray[fence];for(int32_t i = fence;i <listSize - 1;i++)listArray[i] = listArray[i + 1];listSize --;return true;}virtual void setStart(){fence = 0;}virtual void setEnd(){fence = listSize;}virtual void prev(){if(fence > 0) fence -- ;}virtual void next(){if(fence<listSize) fence++;}virtual void leftLength(){return fence;}virtual void rightLength(){return listSize - fence;}virtual bool setPos(int32_t pos){if (pos >=0 && pos <=listSize)fence = pos;}virtual bool getValue(Elem& elem){if(rightLength() == 0) return false;elem = listArray[fence];return true;}virtual void print(){for(int32_t i = 0; i < listSize; i++){if(i == fence)cout << "|" << " " << listArray[i] << " ";elsecout << listArray[i] << " ";}}}
扩展:有序顺序表SAList
相比较于
//protected:自主继承,SAList只暴露需要暴露的方法给用户使用。//如果使用public则顺序表的全部方法都可以使用,这会导致一个问题://有序表顺序表的插入只能有一种即按顺序的插入,//所以有序顺序表就不可以使用比如append方法了。template<class Elem, class Compare>class SAList : protected AList<Elem>{public:SAList(int size = DefaultListSize):AList<Elem>(size){};~SAList(){};AList<Elem>::clear;bool insert(const Elem& elem){Elem curr;for(setStart(); getValue(curr);next()){if(!Compare::lt(curr, elem)) break;}return AList<Elem>::insert(item);}AList<Elem>::remove;AList<Elem>::setStart;AList<Elem>::setEnd;AList<Elem>::prev;AList<Elem>::next;AList<Elem>::leftLength;AList<Elem>::rightLenth;AList<Elem>::setPos;AList<Elem>::getValue;AList<Elem>::print;}
2、链表_单向链表LList
单向链表的节点结构和链表结构如下图,注意链表初始就有一个head首节点也是一个空节点,第一个数据在head节点之后。
节点结构C++实现
//链表节点template<class Elem>class Link{Link *next;Elem element;Link(const Elem& elemval, Link* nextval = NULL){element = elemval;next = nextval;}Link(Link* nextval = NULL){next = nextval;}}
链表结构C++实现
template<class Elem>class LList : public List<Elem>{private:Link<Elem> *head;Link<Elem> *tail;Link<Elem> *fence;int leftcnt;int rightcnt;void init(){fence = tail = head = new Link<Elem>;leftcnt = rightcnt = 0;}void removeall(){while(head != NULL){fence = head;head = head->next;delete fence;}}public:LList(int size = DefaultListSize){init();}~LList(){removeall();}virtual void clear(){removeall();init();}bool insert(const Elem& elem){fence->next = new Link(elem, fence->next);rightcnt++;return true;}bool append(const Elem& elem){tail->next = new Link(elem, NULL);rightcnt++;return true;}bool remove(Elem& elem){if(fence->next == NULL) return false;elem = fence->next->element;Link<Elem>* ltemp = fence->next;fence->next = fence->next->next;if(tail == ltemp) tail = fence;delete ltemp;rightcnt--;return true;}void setStart(){fence = head;rightcnt += leftcnt;leftcnt = 0;}void setEnd(){fence = tail;leftcnt += rightcnt;rightcnt = 0;}void prev(){if(fence == head) return;Link<Elem*> temp = head;while(temp->next != fence) temp = temp->next;fence = temp;rightcnt--;leftcnt++;}void next(){if(fence ~= tail){fence = fence->next;rightcnt--;leftcnt++;}}int leftLength() { return leftcnt; }int rightLength() { return rightcnt; }bool setPos(int32_t pos){if((pos < 0) || (pos > (rightcnt + leftcnt))) return false;fence = head;for(int32_t i = 0; i < pos; i++) fence = fence->next;rightcnt = rightcnt + leftcnt - pos;leftcnt = pos;return true}bool getValue(Elem& elem){if(rightLength() == 0) return false;elem = fence->element;return true;}void print(){Link<Elem>* temp = NULL;for(temp = head; temp != fence; temp = temp->next){cout << temp->next->element << " ";}cout << "| ";for(;temp->next != NULL;temp = temp->next){cout << temp->next->element << " ";}}
扩展:有“缓存池”的链表
Link:链表节点类。
用一个Link* freeelist作为节点“缓存池”,freelist其实是一个链表表头,这个链表缓存了可用的链表节点。重载节点的new/delete:
new时:从缓存池去先尝试获取(从freelist的表头获取),如果freelist空了,就调用默认new直接返回内存地址。
delete时:放入缓存池(插入到freelist的表头)。
template<class Elem> class Link{private:static Link<Elem>* freelist;public:Elem element;Link* next;Link(const Elem& elemval, Link* nextval = NULL){element = elemval;next = nextval;}Link(Link* nextval = NULL){next = nextval;}void* operator new(size_t); //先从缓存池获取,不然就newvoid* operator delete(void *); //回收给缓存池}//Link.cpptemplate<class Elem>Link<Elem>* Link<Elem>::freelist = NULL;template<Elem>void* Link<Elem>::operator new(size_t){if(freelist == NULL) return ::new Link; //这里new的最终会在delete的时候回收给freelistLink<Elem>* temp = freelist;freelist = freelist->next;return temp;}template<Elem>void Link<Elem>::operator delete(void* ptr){((Link<Elem>*)ptr)->next = freelist;freelist = (Link<Elem>*)ptr;}
3、链表_双向链表LList
双向链表结构以及节点结构如下图,注意链表初始就有一个head节点,第一个数据在head节点之后。
双向链表的插入
双向链表的删除
节点结构C++实现
template<class Elem> class Link{private:static Link<Elem>* freelist; //节点缓存池public:Elem element;Link* next;Link* prev;Link(const Elem& e, Link* prev = NULL, Link* next = NULL){element = e;this->prev = prev;this->next = next;}Link(Link* prev = NULL, Link* next = NULL){prev = prev;next = next;}void* operator new(size_t){if(freelist == NULL) return ::new Link;Link<Elem>* temp = freelist;freelist = freelist->next;}void operator delete(void* ptr){((Link<Elem>*)ptr)->next = freelist;freelist = (Link<Elem>*)ptr;}}
链表结构C++实现
template<class Elem>class LList : public List<Elem>{private:Link<Elem> *head;Link<Elem> *tail;Link<Elem> *fence;int leftcnt;int rightcnt;void int(){fence = tail = head = new Link<Elem>;leftcnt = rightcnt = 0;}void removeall(){while(head != NULL){fence = head;head = head->next;delete fence;}}public:LList(int size = DefaultListSize){init();}~LList(){removeall();}virtual void clear(){removeall();init();}bool insert(const Elem& elem){fence->next = new Link(elem, fence,fence->next);if(fence->next->next != NULL)fence->next->next->prev = fence->next;if(tail == fence)tail = fence->next;rightcnt++;return true;}bool append(const Elem& elem){tail = tail->next = new Link<Elem>(elem, tail, NULL);rightcnt++;return true}bool remove(Elem& elem){if(fence->next == NULL) return false; //rightcnt == 0elem = fence->next->element;Link<Elem>* temp = fence->next;if(temp->next != NULL) temp->next->prev = fence;else tail = fence;fence->next = temp->next;delete temp;rightcnt--;return true;}void setStart(){fence = head;rightcnt += leftcnt;leftcnt = 0;}void setEnd(){fence = tail;leftcnt += rightcnt;rightcnt = 0;}void prev(){if(fence == head) return;fence = fence->prev;rightcnt--;leftcnt++;}void next(){if(fence ~= tail){fence = fence->next;rightcnt--;leftcnt++;}}int leftLength() { return leftcnt; }int rightLength() { return rightcnt; }bool setPos(int32_t pos){//使用leftcnt == posif((pos < 0) || (pos > (rightcnt + leftcnt))) return false;fence = head;for(int32_t i = 0; i < pos; i++) fence = fence->next;rightcnt = rightcnt + leftcnt - pos;leftcnt = pos;return true}bool getValue(Elem& elem){if(rightLength() == 0) return false;elem = fence->element;return true;}void print(){Link<Elem>* temp = NULL;for(temp = head; temp != fence; temp = temp->next){cout << temp->next->element << " ";}cout << "| ";for(;temp->next != NULL;temp = temp->next){cout << temp->next->element << " ";}}
扩展:“节省空间”的双向链表
参考:https://www.cnblogs.com/tiny656/p/4108976.html
一般双向链表节点保存prev和next两个指针,空间两倍于单向链表。
根据异或函数(XOR)的如下性质:
(L^R)^R = L
(L^R)^L = R
如下是链表结构,每个节点保存一个Link*指针xorPtr,值为前后两个节点的异或。则:
C = B->xorPtr ^ A
A = B->xorPtr ^ C
//节点结构如下:template<class Elem>class Link{private:Link<Elem>* freelist;public:Elem element;Link<Elem>* xorPtr; //保存的是上一个节点和一个节点的异或值。public:Link(const Elem& e,Link* prev, Link* next){element = e;xorPtr = prev ^ next;}Link(Link* prev, Link* next){xorPtr = prev ^ next;}}
