- 链表节点的ADT接口
列表节点模板类:
typedef int Rank
#define ListNodePosi(T) ListNode<T>*//列表节点位置
template <typename T> struct ListNode {//双向链表形式实现
//成员
T data; ListNodePosi(T) pred; ListNodePosi(T) succ;
//构造函数
ListNode() {};//针对header和trailer
ListNode(T e, ListNodePosi(T) p = NULL, ListNodePosi(T) s = NULL) : data(e), pred(p), succ(s) {}
//操作接口
ListNodePosi(T) insertAsPred(T const& e);
ListNodePosi(T) insertAsSucc(T const& e);
};
- 链表的ADT接口
列表的形式:头尾结点始终存在,但不可见(需要封装),由他们(header->succ或者trailer->pred)来寻找链表;首末节点及其中间的节点可见。
列表的模板类:
typedef int Rank
#define ListNodePosi(T) ListNode<T>*//列表节点位置
template <typename T> struct ListNode {//双向链表形式实现
//成员
T data; ListNodePosi(T) pred; ListNodePosi(T) succ;
//构造函数
ListNode() {};//针对header和trailer
ListNode(T e, ListNodePosi(T) p = NULL, ListNodePosi(T) s = NULL) : data(e), pred(p), succ(s) {}
//操作接口
ListNodePosi(T) insertAsPred(T const& e);
ListNodePosi(T) insertAsSucc(T const& e);
};
# include "ListNode.h"
template <typename T> class List{
private:
int _size; ListNodePosi(T) header; ListNodePosi(T) trailer;//封装:规模、首末节点
protected:
void init();//链表初始化
int clear();//清除所有节点
void copyNOdes(ListNodePosi(T), int);//复制链表自位置p起的n项
void merge(ListNodePosi(T)&, int, List<T>&, ListNodePosi(T), int);
void mergeSort(ListNodePosi(T)&, int);//从p开始连续的n项归并排序
void selectionSort(ListNodePosi(T), int);
void insertionSort(ListNodePosi(T), int);
public:
//构造函数
List() {init();}
List(List<T> const& L);//整体复制链表L
List(List<T> const& L, Rank r, int n);//复制链表L自位置r起的n项
List(ListNodePosi(T) p, int n); //复制链表位置p起的n项
//析构函数
~List();、
//只读访问接口
Rank size() const {return _size;}//规模
bool empty() const {return _size <= 0;}
T& operator[] (Rank r) const;//重载运算符[],支持寻秩访问
ListNodePosi(T) first() const {return header->succ;}//首节点
ListNodePosi(T) last() const {return trailer->pred;}//末节点
bool valid(ListNodePosi(T) p) //判断p是否对外合法
{return p && (trailer != p) && (header != p);}
int disordered() const;//判断列表是否已经排序
ListNodePosi(T) find (T const& e) const{//无序列表查找
return find (e, _size, trailer);
}
ListNodePosi(T) find (T const& e, int n, ListNodePosi(T) p) const;
ListNodePosi(T) search ( T const& e, int n, ListNodePosi(T) p ) const; //有序区间查找
ListNodePosi(T) selectMax ( ListNodePosi(T) p, int n ); //在p及其n-1个后继中选出最大者
ListNodePosi(T) selectMax() { return selectMax ( header->succ, _size ); } //整体最大者
//可写访问接口
ListNodePosi(T) insertAsFirst ( T const& e ); //将e当作首节点插入
ListNodePosi(T) insertAsLast ( T const& e ); //将e当作末节点插入
ListNodePosi(T) insertA ( ListNodePosi(T) p, T const& e ); //将e当作p的后继插入(After)
ListNodePosi(T) insertB ( ListNodePosi(T) p, T const& e ); //将e当作p的前驱插入(Before)
T remove ( ListNodePosi(T) p ); //删除合法位置p处的节点,返回被删除节点
void merge ( List<T> & L ) { merge ( header->succ, _size, L, L.header->succ, L._size ); } //全列表归并
void sort ( ListNodePosi(T) p, int n ); //列表区间排序
void sort() { sort ( first(), _size ); } //列表整体排序
int deduplicate(); //无序去重
int uniquify(); //有序去重
void reverse(); //前后倒置
//遍历
void traverse ( void (* ) ( T& ) ); //遍历,依次实施visit操作(函数指针,只读或局部性修改)
template <typename VST> //操作器
void traverse ( VST& ); //遍历,依次实施visit操作(函数对象,可全局性修改)
};
- 链表的实现
(1)默认构造函数
链表初始化:
template <typename T>
void List<T> :: init() {
header = new ListNode<T>;
trailer = new ListNode<T>;
header->succ = trailer; header->pred = NULL;
trailer->pred = header; trailer->succ = NULL;
_size = 0;
}
(2)寻秩访问,重载操作符[]
template <typename T>
T& List<T> :: operator[] (Rank r) const {
ListNodePosi(T) p = first();
while(0 < r--)
p = p->succ;
return p->data;
}
寻秩访问效率太低。
(3)查找
使用区间查找:find(e,p,n)
p的n个前驱中寻找。
区间查找的特例是:find(e)
。
template <typename T>
ListNodePosi(T) List<T> :: find(T const& e, int n, ListNodePosi(T) p) const {
while(0 < n--)
if(e == (p = p->pred)->data)
return p;
return NULL;
}
(4)插入
多种插入方法:
template<typename T>
ListNodePosi(T) List<T> :: insertAsFirst (T const& e){
_size++;
return head->insertAsSucc(e);//e作为首节点插入
}
template<typename T>
ListNodePosi(T) List<T> :: insertAsLast (T const& e){
_size++;
return trailer->insertAsPred(e);//e作为末节点插入
}
template<typename T>
ListNodePosi(T) ListNodePosi<T> :: insertA (ListNodePosi(T) p, T const& e){
_size++;
return p->insertAsSucc(e);//e作为p的后继插入
}
template<typename T>
ListNodePosi(T) ListNodePosi<T> :: insertB (ListNodePosi(T) p, T const& e){
_size++;
return p->insertAsPred(e);//e作为p的前驱插入
}
前驱插入:
template<typename T>
ListNodePosi(T) ListNode<T> :: insertAsPred(T const& e){
ListNodePosi(T) x = new ListNode(e, pred, this);
pres->succ = x; pred = x;//this.pred->succ = x; this.pred = x;
return x;
}
其中(3)和(4)的步骤不能反,因为链表不能断。
后继插入:
template<typename T>
ListNodePosi(T) ListNode<T> :: insertAsSucc(T const& e){
ListNodePosi(T) x = new ListNode(e, this, succ);
succ->pred = x; succ = x;
return x;
}
(5)链表的复制构造
template<typename T>
void List<T> :: copyNOdes(ListNodePosi(T) p, int n){
init();
while(n--){
insertAsLast(p->data);
p = p->succ;
}
}
(6)删除
template <typename T>
T List<T> :: remove (ListNodePosi(T) p){
T e = p->data;//备份
p->pred->succ = p->succ; p->succ->pred = p->pred;
delete p;
_size--;
return e;
}
(7)析构
template <typename T>
List<T> :: ~List(){
clear();
delete header;
delete trailer;
}
template <typename T>
int List<T> :: clear(){
int oldSize = _size;
while(0 < _size)
remove(head->succ);
return oldSize;
}
(8)删除重复元素
1)列表:
template <typename T>
int List<T> :: deduplicate(){
if(_size < 2)
return 0;
int oldSize = _size;
ListNodePosi(T) p = header; Rank r = 0;
while(trailer != (p = p->succ)){
ListNodePosi(T) q = find(p->data, r, p);
q ? remove(q) : r++;
}
return oldSize - _size;
}
2)有序列表
template <typename T>
int List<T> :: uniquify(){
if(_size < 2)
return 0;
int oldSize = _size;
ListNodePosi(T) p = first(); ListNodePosi(T) q;
while(trailer != (q = p->succ))
if(p->data != q->data)
p = q;
else remove(q);
return oldSize - _size;
}
(9)遍历
template <typename T>
void List<T> :: traverse(void (*visit) (T&)){
for (ListNodePosi(T) p = header->succ; p != trailer; p = p->succ)
visit (p->data);
}
template <typename T> template <typename VST>
void List<T> :: traverse(VST& visit){
for (ListNodePosi(T) p = header->succ; p != trailer; p = p->succ)
visit (p->data);
}
(10)查找
template <typename T>
ListNodePosi(T) List<T> :: search(T const& e, int n, ListNodePosi(T) p) const{
while (0 <= n--)
if (((p = p->pred)->data) <= e) break;
return p;
}