线性表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大小-1
virtual void next() = 0; //fence往右移动一个,right大小-1
virtual int leftLength() const = 0; //left的大小
virtual int rightLength() const = 0; //right的大小
virtual bool setPos(int pos) = 0; //设置fence使leftLength() = pos
virtual bool getValue(Elem&) const = 0; //返回right的第一个elem,没有bool=false
virtual 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] << " ";
else
cout << 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); //先从缓存池获取,不然就new
void* operator delete(void *); //回收给缓存池
}
//Link.cpp
template<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的时候回收给freelist
Link<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 == 0
elem = 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 == 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 << " ";
}
}
扩展:“节省空间”的双向链表
参考: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;
}
}