【二】数据结构之List

来源:互联网 发布:郫都区人民政府 知乎 编辑:程序博客网 时间:2024/06/05 18:43

【二】数据结构之List

数据结构中,线性表无独有偶,除了Vector还有另外一种ADT,就是我们要讨论的List,与向量Vector有所不同,列表List不在是系统连续的内存空间,也就是说不是基于数组来实现的了,尽管在物理上不是线性的,但是抽象层次上,List在逻辑上依旧是现行表,因此List优化了Vector插入,删除操作的劣势,但是在查找方面却不如Vector的二分查找来的快。
List有哪些接口呢?

这里写图片描述

恩,接下来,给出具体的实现,注释都很详细,很容易理解。

节点的实现如下:

#ifndef LISTNODE_H#define LISTNODE_Htypedef 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);//紧靠当前节点之后插入新节点};//类函数定义template <typename T>//将e紧靠当前节点之前插入于当前节点所属列表(设有哨兵头节点header)ListNodePosi(T) ListNode<T>::insertAsPred(T const& e){    ListNodePosi(T) x = new ListNode(e, pred, this);//创建新节点    pred->succ = x; pred = x;//设置正向链接    return x;//返回新节点的位置}template <typename T>//将e紧靠当前节点之后插入于当前节点所属列表(设有哨兵头节点trailer)ListNodePosi(T) ListNode<T>::insertAsSucc(T const& e){    ListNodePosi(T) x = new ListNode(e, this, succ);//创建新节点    succ->pred = x; succ = x;//设置反向链接    return x;//返回新节点的位置}#endif // !LISTNODE_H

列表的实现如下:

#ifndef LIST_H#define LIST_H#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);//归并排序    void selectionSort(ListNodePosi(T), int);//选择排序    void insertionSort(ListNodePosi(T), int);//插入排序public:    //构造函数    List(){ init(); }    List(List<T> const& 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 };//判空    ListNodePosi(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) const{//有序列表查找        return search(e, _size, trailer);    }    ListNodePosi(T) search(T const& e, int n, ListNodePosi(T) p)const;//有序区间查找    ListNodePosi(T) selectMax(ListNodePosi(T), 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(first(), size, L, L.first, 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操作(函数对象)};//List//类函数的定义//初始化template <typename T>void List<T>::init(){    header = new ListNode<T>();    trailer = new ListNode<T>();    header->succ = trailer;    trailer->pred = trailer;    _size = 0;}//无序表的查找template <typename T>ListNodePosi(T) List<T>::find(T const& e, int n, ListNodePosi(T) p) const{    while (0 < n--){//对于p的n个最近的真前驱,从右向左        if (e == (p = p->pred)->data) return p;//逐个比对,直至命中或越界    }    return NULL;//p越界意味着失败}//失败时返回NULL//作为首节点插入template <typename T> ListNodePosi(T) List<T>::insertAsFirst(T const& e){    _size++; return header->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) List<T>::insertA(ListNodePosi(T) p, T const& e){    _size++; return p->insertAsSucc(e);//e当做p的后继插入}//作为当前节点的前驱插入template <typename T>ListNodePosi(T) List<T>::insertB(ListNodePosi(T) p, T const& e){    _size++; return p->insertAsPred(e);//e当做p的前继插入}//基本接口template <typename T>void List<T>::copyNodes(ListNodePosi(T) p, int n){    init();//创建头、尾节点并做初始化    while (n--){//将起自p的n项依次作为末节点插入        insertAsLast(p->data); p = p->succ;    }}//重载下标操作符,以通过秩直接访问列表节点(虽方便,效率低,需慎用)template <typename T>ListNodePosi(T) List<T>::operator[] (Rank r) const{    ListNodePosi(T) p = first();//从首节点出发    while (0 < r--)p = p->succ;//顺数第r个节点即是    return p;//目标节点,返回其中所存元素}//重载构造函数template <typename T>List<T>::List(List<T> const & L){    copyNodes(L.first(), L._size);}template <typename T>List<T>::List(List<T> const & L, int r, int n){    copyNodes(L[r], n);}//删除合法节点p,返回其数值template <typename T>T List<T>::remove(ListNodePosi(T) p){    T e = p->data;//备份待删除节点的数值(假定T类型可直接赋值)    p->pred->succ = p->succ; p->succ->pred = p->pred;//后继、前驱    delete p; _size--;//释放节点,更新规模    return e;//返回备份的数值}//析构函数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(header->succ);    return oldSize;}//剔除无序列表中的重复节点template <typename T>int List<T>::deduplicate(){    if (_size < 2)return 0;//平凡列表自然无重复    int oldSize = _size;//记录原始规模    ListNodePosi(T) p = header; Rank r = 0;//p从首节点开始    while (trailer != (p = p->succ)){//依次直到末节点        ListNodePosi(T) q = find(p->data, r, p);//在p的r个真前驱中查找雷同者        q ? remove(q) : r++;//若的确存在,则删除之,否则秩加一    }//assert:循环过程中的任意时刻p的所有前驱互不相同    return oldSize - _size;//列表规模变化量,即被删除元素的总数}//借助函数指针机制遍历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);}//有序列表去重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;}//只需要遍历整个列表一趟,O(n)//在有序表内p节点的n个真前驱中找到不大于e的最后者template <typename T>ListNodePosi(T) List<T>::search(T const&e, int n, ListNodePosi(T) p)const{    //assert:0<=n<=Rank(p)<_size    do{        p = p->pred; n--;    } while ((-1 < n) && (e < p->data));//逐个比较直到命中或者越界    return p;}//失败时,返回区间左边界的前驱(可能是header)//列表的选择排序算法:对起始于位置p的n个元素排序template<typename T>void List<T>::selectionSort(ListNodePosi(T) p, int n){    ListNodePosi(T) head = p->pred; ListNodePosi(T) tail = p;    for (int i = 0; i < n; i++)tail = tail->succ;//待排序区间(head,tail)    while (1 < n){        ListNodePosi(T) max = selectMax(head->succ, n);        insertB(tail, remove(max));        tail = tail->pred;        n--;    }}//从起始位置p的n个元素中选出最大者template<typename T>ListNodePosi(T) List<T>::selectMax(ListNodePosi(T) p, int n){    ListNodePosi(T) max = p;    for (ListNodePosi(T) cur = p; 1 < n; n--){        if (!lt((cur = cur->succ)->data, max->data))            max = cur;    }    return max;}//a小于b?template<typename T>bool lt(T a, T b){    return a < b;}//列表的插入排序算法:对起始于位置p的n个元素排序template<typename T>void List<T>::insertionSort(ListNodePosi(T) p, int n){    for (int r = 0; r < n; r++){        insertA(search(p->data, r, p), p->data);        p = p->succ; remove(p->pred);    }}//有序列表的归并:当前列表中自p起的n个元素,与列表L中自q起的m个元素归并template <typename T>void List<T>::merge(ListNodePosi(T) & p, int n, List<T>&L, ListNodePosi(T) q, int m){    ListNodePosi(T) pp = p->pred;//借助前驱,以便返回前。。。    while (0 < m){//在q尚未移出区间之前        if ((0 < n) && (p->data <= q->data)){//若p仍在区间内且v(p)<=v(q),则            if (q == (p = p->succ))//p归入合并的列表,并替换为其直接后继                break;            n--;        }        else{//若p已经超出了右界或者v(q)<v(p),则            insertB(p, L.remove((q = q->succ)->pred));//将q转移至p之前            m--;        }    }    p = pp->succ;//确定归并后区间的(新)起点}//列表的归并排序算法:对于起始于位置p的n个元素排序template<typename T>void List<T>::mergeSort(ListNodePosi(T) &p, int n){    if (n < 2) return;//若待排序范围已足够小,则直接返回;否则...    int m = n >> 1;//以中点为界    ListNodePosi(T) q = p;    for (int i = 0; i < m; i++)q = q->succ;//均分列表    mergeSort(p, m); mergeSort(q, n - m);//对前、后子列表分别排序    merge(p, m, *this, q, n - m);//归并}//注意:排序后,p依然指向归并后区间的(新)起点//判断列表是否有序template<typename T>int List<T>::disordered()const{    int n=0;    for (ListNodePosi(T) p = header->succ; p->succ != trailer; p = p->succ){        if (p->data > p->succ->data)            n++;    }    return n;}//返回0表示已有序#endif // !LIST_H

这里先给出List的实现,以后再介绍Vector,List等数据结构的具体应用。

0 0
原创粉丝点击