C++ 数据结构学习 ---- 列表

目录

1.头文件

1.1列表头文件

1.2列表节点头文件

2.列表类

2.1列表类

2.2初始化

2.3打印输出

2.4析构函数

2.5清空

2.6删除

2.7重载[ ]

2.8查找(无序)

2.9插入

2.10去重

2.11逆序对判断

2.12复制方法

2.13遍历

2.14排序

2.15查找(有序)

2.16插入排序

2.17最大值

2.18交换

2.19选择排序

2.20归并排序

2.21去重(有序)

2.22递增减半

3.主函数

4.运行结果截图


1.头文件

1.1列表头文件

#include "ListNode.h"//引入节点头文件
#include <ctime>


template <typename T> class List { //列表模板类

private:
    int _size; ListNodePosi<T> header, trailer; //规模、头哨兵、尾哨兵

protected:
    void init(); //列表创建时的初始化
    int clear(); //清除所有节点
    void copyNodes(ListNodePosi<T>, int); //复制列表中自位置p起的n项
    ListNodePosi<T> merge(ListNodePosi<T>&, int, List<T>&, ListNodePosi<T>&, int); //归并
    void mergeSort(ListNodePosi<T>&, int); //对从p开始连续的n个节点归并排序
    void selectionSort(ListNodePosi<T>, int); //对从p开始连续的n个节点选择排序
    void insertionSort(ListNodePosi<T>, int); //对从p开始连续的n个节点插入排序
    void radixSort(ListNodePosi<T>, int); //对从p开始连续的n个节点基数排序

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);
    } //将头、尾节点等同于NULL
    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> 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> insert(ListNodePosi<T> p, T const& e); //将e当作p的后继插入
    ListNodePosi<T> insert(T const& e, ListNodePosi<T> p); //将e当作p的前驱插入
    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 Print(); //打印列表的节点值
 // 遍历
    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; header->pred = NULL;
    trailer->pred = header; trailer->succ = NULL;
    _size = 0; //记录规模
}

//打印节点的值
template <typename T> void List<T>::Print() {
    ListNodePosi<T> p = header->succ;
    while (p != trailer) {//因为存在尾哨兵,所以安全
        std::cout << p->data << " ";//输出节点的值
        p = p->succ;//向后移动
    }
    std::cout<<std::endl;//换行
}

//析构函数 所有销毁节点
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> T List<T>::remove(ListNodePosi<T> p) { //删除合法节点p,返回其数值
    T e = p->data; //备份待删除节点的数值(假定T类型可直接赋值)
    p->pred->succ = p->succ; //被删除节点的前驱的后继====被删除节点的后继
    p->succ->pred = p->pred; //被删除节点的后继的前驱====被删除节点的前驱
    delete p; _size--; //删除节点,释放空间,更新规模
    return e; //返回备份的数值
}


//重载下标“ [ ] ”
template<typename T> 
T& List<T>::operator[] (Rank r) const {
    ListNodePosi<T> p=first();
    while (0 < r--)p = p->succ;
    return p->data;
}



//无序寻找
template <typename T> //在无序列表内节点p(可能是trailer)的n个(真)前驱中,找到等于e的最后者
ListNodePosi<T> List<T>::find(T const& e, int n, ListNodePosi<T> p) const {
    while (0 < n--) //(0 <= n <= rank(p) < _size)对于p的最近的n个前驱,从右向左
        if (e == (p = p->pred)->data) return p; //逐个比对,直至命中或范围越界
    return NULL; //p越出左边界意味着区间内不含e,查找失败
} //失败时,返回NULL




//插入
//头插入
template<typename T> ListNodePosi<T> List<T>::insertAsFirst(T const& e) {
    _size++;
    return header->insertAsSucc(e);
}
//尾插入
template<typename T> ListNodePosi<T> List<T>::insertAsLast(T const& e) {
    _size++;
    return trailer->insertAsPred(e);
}
//前驱插入
template<typename T> ListNodePosi<T> List<T>::insert(T const& e, ListNodePosi<T> p) {
    _size++;
    return p->insertAsPred(e);
}
//后继插入
template<typename T> ListNodePosi<T> List<T>::insert(ListNodePosi<T> p, T const& e) {
    _size++;
    return p->insertAsSucc(e);
}


//无序 唯一化
template<typename T> int List<T>::deduplicate() {
    if (_size < 2) return 0;
    int oldSize = _size;
    ListNodePosi<T> p = header;//  ListNodePosi<T> p = first();
    Rank r = 0;
    while (trailer != (p = p->succ)) {//O(n)
        ListNodePosi<T> q = find(p->data, r, p);//此时q与p雷同,但删除前者更为简明
        q ? remove(q) : r++;//r为无重前缀的长度
    }
    return oldSize - _size;//删除元素总数
}


//是否逆序
template <typename T> int List<T>::disordered() const{
    ListNodePosi<T> h = first();
    int a = -1;
    while (h!=trailer)
    {
        if (h->data > h->succ->data)
            a++;
        h = h->succ;
    }
    std::cout << "存在逆序对:" << a<<std::endl;
    return a;
}

//复制方法
template <typename T> //列表内部方法:复制列表中自位置p起的n项
void List<T>::copyNodes(ListNodePosi<T> p, int n) { //p合法,且至少有n-1个真后继节点
    init(); //创建头、尾哨兵节点并做初始化
    while (n--) { insertAsLast(p->data); p = p->succ; } //将起自p的n项依次作为末节点插入
}
template <typename T> //复制列表中自位置p起的n项
 List<T>::List(ListNodePosi<T> p, int n) { 
     copyNodes(p,n);
}
 template <typename T> //整体复制列表L
 List<T>::List(List<T>const & L ) {
     copyNodes(L.first(), L._size);
 }
 template <typename T> //复制L中第r项起的项  r+n <= L._size
 List<T>::List(List<T>const& L,int r,int n) {
     copyNodes(L[r],n);
 }


 //遍历函数
 template<typename T> void List<T>::traverse( void(*visit) (T&) ) {//借助函数指针机制遍历
     ListNodePosi<T> p = first();
     while (p!=trailer){
    //for (ListNodePosi<T> p = header->succ; p != trailer; p = p->succ) visit(p->data);
         visit(p->data);
         p = p->succ;
     }
 }
 template<typename T> template<typename VST> //元素类型、操作器
 void List<T>::traverse(VST& visit) {//借助函数对象机制遍历
     ListNodePosi<T> p = first();
     while (p != trailer) {
         visit(p->data);
         p = p->succ;
     }
 }


 //排序接口
 template <typename T> void List<T>::sort(ListNodePosi<T> p, int n) {
    
     srand((int)time(NULL));//随机数种子
     switch (rand()%3)
     {
        case 0:
            std::cout << "调用插入排序后前:";
            std::cout << std::endl;
            Print(); disordered();
            std::cout << "调用插入排序后:";
            insertionSort(p, n);
            std::cout << std::endl;
            Print(); disordered();
            break;
        case 1:
            std::cout << "调用选择排序前:";
            std::cout << std::endl;
            Print(); disordered();
            std::cout << "调用选择排序后:";
            selectionSort(p, n);
            std::cout << std::endl;
            Print(); disordered();
            break;
        default :
            std::cout << "调用归并排序前:";
            std::cout << std::endl;
            Print(); disordered();
            std::cout << "调用归并排序后:";
            mergeSort(p, n);
            std::cout << std::endl;
            Print(); disordered();
            break;
     }
 }

 //有序向量查找
 template <typename T> //在有序列表内节点p(可能是trailer)的n个(真)前驱中,找到不大于e的最后者
 ListNodePosi<T> List<T>::search( T const& e,int n,ListNodePosi<T> p)const {
     //0 <= n <= Rank(p) < _size
     while (-1 < n--) {//对于p的n个前驱,从左往右进行比较
         if ( (p = p->pred)->data <= e) break;//直到命中元素,数值越界或范围越界
     }
     return p;//失败时,返回区间左边界的前驱(可能是header)——调用者可通过valid()判断成功与否
 }

 //插入排序
 template <typename T> //对列表中起始于位置p、宽度为n的区间做插入排序
 void List<T>::insertionSort(ListNodePosi<T> p, int n) { //valid(p) && rank(p) + n <= size
     for (int r = 0; r < n; r++) { //逐一为各节点
         insert(search(p->data, r, p), p->data); //查找适当的位置并插入
         p = p->succ; remove(p->pred); //转向下一节点
     }
 }

 //找出在列表中的最大值
 template <typename T> //从起始于位置p的n个元素中选出最大者
 ListNodePosi<T> List<T>::selectMax(ListNodePosi<T> p, int n) {
     ListNodePosi<T> max = p; //最大者暂定为首节点p
     while (  0 < n--) {//从首节点p出发,将后续节点逐一与max比较
         if (max->data <= p->data) max = p;//更新最大元素位置记录
         p = p->succ;//向后移动指针
     }
     return max; //返回最大节点位置
 }

 template <class T> void swap(T& x, T& y)
 {
     T tmp = x;
     x = y;
     y = tmp;
 }

 //选择排序
 template <typename T> //对列表中起始于位置p、宽度为n的区间做选择排序
 void List<T>::selectionSort(ListNodePosi<T> p, int n) { //valid(p) && rank(p) + n <= size
  
     ListNodePosi<T> head = header, tail = trailer; //待排序区间为(head, tail)
     while (1 < n) { //在至少还剩两个节点之前,在待排序区间内
         ListNodePosi<T> max = selectMax(head->succ, n); //找出最大者(歧义时后者优先)
         //这里要特别注意,因为有可能存在节点会插入到头哨兵节点之后形成新的首节点,导致
         //p的指针出现问题,所以不能在原始的区间上继续找最大节点,此处使用哨兵的后继指针,
         //用来保证指针的正确性
         //将其移至无序区间末尾(作为有序区间新的首元素)
         if(tail->pred != max)
         swap(tail->pred->data,max->data);// insert(remove(max), tail);
         //插入与删除中存在new 和 delete 这些操作比一般的操作多出两个数量级
         tail = tail->pred; n--;
     }
 }


 //归并排序
 template<typename T>//列表的归并排序算法:对起始于位置p的n个元素排
 void List<T>::mergeSort(ListNodePosi<T> &p,int n) {//valid(p) && rank(p) + n <= size
     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); //前、后子列表各分别排序
     p= merge(p,m,*this,q,n-m);//归并函数
 }//注意:排序后,p依然指向归并后区间的(新)起点
 

 //归并函数
 template <typename T> //有序列表的归并:当前列表中自p起的n个元素,与列表L中自q起的m个元素归并
 ListNodePosi<T> List<T>::merge(ListNodePosi<T> &p, int n, List<T>& L, ListNodePosi<T>& q, int m) {
     // assert:  this.valid(p) && rank(p) + n <= size && this.sorted(p, n)
     //          L.valid(q) && rank(q) + m <= L._size && L.sorted(q, m)
     // 注意:在被mergeSort()调用时,this == &L && rank(p) + n = rank(q)
     ListNodePosi<T> pp = p->pred; //归并之后p可能不再指向首节点,故需先记忆,以便在返回前更新
     while ((0 < m) && (q != p)) //q尚未出界(或在mergeSort()中,p亦尚未出界)之前
         if ((0 < n) && (p->data <= q->data)) //若p尚未出界且v(p) <= v(q),则
         {
             p = p->succ; n--;
         } //p直接后移,即完成归入
         else //否则,将q转移至p之前,以完成归入
         {
             q = q->succ;
             insert(remove(q ->pred),p);
             m--;
         }
     return pp->succ; //更新的首节点
 }

 template<typename T> int List<T>::uniquify() {
     if (_size < 2) return 0;//就一个节点
     int oldSize = _size;//记录原规模
     ListNodePosi<T> p = header; ListNodePosi<T> q;//p为起点,q为p的后继
     while (trailer != (q=p->succ))
     {
         if (p->data != q->data) p = q;//若互异,转入下一节点
         else remove(q);//删除雷同的后者
     }
     return oldSize - _size;//被删的元素总数
 }

 //递增类对象
 template<typename T> struct Increase{
     virtual void operator ()(T& e) { e++; }//T可直接递增或已经重载了++
 };
 //递增函数
 template<typename T> void increase(List<T>& L) {
     L.traverse(Increase<T>());//遍历递增
 }
 //减半类对象
 template<typename T> struct Half {
     virtual void operator ()(T& e) { e >>= 1; }
 };
 //减半函数
 template<typename T> void half(List<T>& L) {
     L.traverse(Half<T>());//遍历减半
 }


 

1.2列表节点头文件

//定义节点
using Rank = int; //秩
template <typename T> struct ListNode;
template <typename T> using ListNodePosi = 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; //返回新节点的位置
}

2.列表类

2.1列表类

template <typename T> class List { //列表模板类

private:
    int _size; ListNodePosi<T> header, trailer; //规模、头哨兵、尾哨兵

protected:
    void init(); //列表创建时的初始化
    int clear(); //清除所有节点
    void copyNodes(ListNodePosi<T>, int); //复制列表中自位置p起的n项
    ListNodePosi<T> merge(ListNodePosi<T>&, int, List<T>&, ListNodePosi<T>&, int); //归并
    void mergeSort(ListNodePosi<T>&, int); //对从p开始连续的n个节点归并排序
    void selectionSort(ListNodePosi<T>, int); //对从p开始连续的n个节点选择排序
    void insertionSort(ListNodePosi<T>, int); //对从p开始连续的n个节点插入排序
    void radixSort(ListNodePosi<T>, int); //对从p开始连续的n个节点基数排序

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);
    } //将头、尾节点等同于NULL
    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> 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> insert(ListNodePosi<T> p, T const& e); //将e当作p的后继插入
    ListNodePosi<T> insert(T const& e, ListNodePosi<T> p); //将e当作p的前驱插入
    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 Print(); //打印列表的节点值
 // 遍历
    void traverse(void (*) (T&)); //遍历,依次实施visit操作(函数指针,只读或局部性修改)
    template <typename VST> //操作器
    void traverse(VST&); //遍历,依次实施visit操作(函数对象,可全局性修改)
}; //List

2.2初始化

//初始化函数
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.3打印输出

//打印节点的值
template <typename T> void List<T>::Print() {
    ListNodePosi<T> p = header->succ;
    while (p != trailer) {//因为存在尾哨兵,所以安全
        std::cout << p->data << " ";//输出节点的值
        p = p->succ;//向后移动
    }
    std::cout<<std::endl;//换行
}

2.4析构函数

//析构函数 所有销毁节点
template <typename T> List<T>::~List() //列表析构器
{
    clear(); delete header; delete trailer;
} //清空列表,释放头、尾哨兵节点

2.5清空

//清空列表函数  只销毁可见节点 无法销毁头尾部哨兵
template <typename T> int List<T>::clear() { //清空列表
    int oldSize = _size;
    while (0 < _size) remove(header->succ); //反复删除首节点,直至列表变空
    return oldSize;
}

2.6删除

//删除节点函数
template <typename T> T List<T>::remove(ListNodePosi<T> p) { //删除合法节点p,返回其数值
    T e = p->data; //备份待删除节点的数值(假定T类型可直接赋值)
    p->pred->succ = p->succ; //被删除节点的前驱的后继====被删除节点的后继
    p->succ->pred = p->pred; //被删除节点的后继的前驱====被删除节点的前驱
    delete p; _size--; //删除节点,释放空间,更新规模
    return e; //返回备份的数值
}

2.7重载[ ]

//重载下标“ [ ] ”
template<typename T> 
T& List<T>::operator[] (Rank r) const {
    ListNodePosi<T> p=first();
    while (0 < r--)p = p->succ;
    return p->data;
}

2.8查找(无序)

//无序寻找
template <typename T> //在无序列表内节点p(可能是trailer)的n个(真)前驱中,找到等于e的最后者
ListNodePosi<T> List<T>::find(T const& e, int n, ListNodePosi<T> p) const {
    while (0 < n--) //(0 <= n <= rank(p) < _size)对于p的最近的n个前驱,从右向左
        if (e == (p = p->pred)->data) return p; //逐个比对,直至命中或范围越界
    return NULL; //p越出左边界意味着区间内不含e,查找失败
} //失败时,返回NULL

2.9插入

//插入
//头插入
template<typename T> ListNodePosi<T> List<T>::insertAsFirst(T const& e) {
    _size++;
    return header->insertAsSucc(e);
}
//尾插入
template<typename T> ListNodePosi<T> List<T>::insertAsLast(T const& e) {
    _size++;
    return trailer->insertAsPred(e);
}
//前驱插入
template<typename T> ListNodePosi<T> List<T>::insert(T const& e, ListNodePosi<T> p) {
    _size++;
    return p->insertAsPred(e);
}
//后继插入
template<typename T> ListNodePosi<T> List<T>::insert(ListNodePosi<T> p, T const& e) {
    _size++;
    return p->insertAsSucc(e);
}

2.10去重

//无序 唯一化
template<typename T> int List<T>::deduplicate() {
    if (_size < 2) return 0;
    int oldSize = _size;
    ListNodePosi<T> p = header;//  ListNodePosi<T> p = first();
    Rank r = 0;
    while (trailer != (p = p->succ)) {//O(n)
        ListNodePosi<T> q = find(p->data, r, p);//此时q与p雷同,但删除前者更为简明
        q ? remove(q) : r++;//r为无重前缀的长度
    }
    return oldSize - _size;//删除元素总数
}

2.11逆序对判断

//是否逆序
template <typename T> int List<T>::disordered() const{
    ListNodePosi<T> h = first();
    int a = -1;
    while (h!=trailer)
    {
        if (h->data > h->succ->data)
            a++;
        h = h->succ;
    }
    std::cout << "存在逆序对:" << a<<std::endl;
    return a;
}

2.12复制方法

//复制方法
template <typename T> //列表内部方法:复制列表中自位置p起的n项
void List<T>::copyNodes(ListNodePosi<T> p, int n) { //p合法,且至少有n-1个真后继节点
    init(); //创建头、尾哨兵节点并做初始化
    while (n--) { insertAsLast(p->data); p = p->succ; } //将起自p的n项依次作为末节点插入
}
template <typename T> //复制列表中自位置p起的n项
 List<T>::List(ListNodePosi<T> p, int n) { 
     copyNodes(p,n);
}
 template <typename T> //整体复制列表L
 List<T>::List(List<T>const & L ) {
     copyNodes(L.first(), L._size);
 }
 template <typename T> //复制L中第r项起的项  r+n <= L._size
 List<T>::List(List<T>const& L,int r,int n) {
     copyNodes(L[r],n);
 }

2.13遍历

//遍历函数
 template<typename T> void List<T>::traverse( void(*visit) (T&) ) {//借助函数指针机制遍历
     ListNodePosi<T> p = first();
     while (p!=trailer){
    //for (ListNodePosi<T> p = header->succ; p != trailer; p = p->succ) visit(p->data);
         visit(p->data);
         p = p->succ;
     }
 }
 template<typename T> template<typename VST> //元素类型、操作器
 void List<T>::traverse(VST& visit) {//借助函数对象机制遍历
     ListNodePosi<T> p = first();
     while (p != trailer) {
         visit(p->data);
         p = p->succ;
     }
 }

2.14排序

//排序接口
 template <typename T> void List<T>::sort(ListNodePosi<T> p, int n) {
    
     srand((int)time(NULL));//随机数种子
     switch (rand()%3)
     {
        case 0:
            std::cout << "调用插入排序后前:";
            std::cout << std::endl;
            Print(); disordered();
            std::cout << "调用插入排序后:";
            insertionSort(p, n);
            std::cout << std::endl;
            Print(); disordered();
            break;
        case 1:
            std::cout << "调用选择排序前:";
            std::cout << std::endl;
            Print(); disordered();
            std::cout << "调用选择排序后:";
            selectionSort(p, n);
            std::cout << std::endl;
            Print(); disordered();
            break;
        default :
            std::cout << "调用归并排序前:";
            std::cout << std::endl;
            Print(); disordered();
            std::cout << "调用归并排序后:";
            mergeSort(p, n);
            std::cout << std::endl;
            Print(); disordered();
            break;
     }
 }

2.15查找(有序)

//有序向量查找
 template <typename T> //在有序列表内节点p(可能是trailer)的n个(真)前驱中,找到不大于e的最后者
 ListNodePosi<T> List<T>::search( T const& e,int n,ListNodePosi<T> p)const {
     //0 <= n <= Rank(p) < _size
     while (-1 < n--) {//对于p的n个前驱,从左往右进行比较
         if ( (p = p->pred)->data <= e) break;//直到命中元素,数值越界或范围越界
     }
     return p;//失败时,返回区间左边界的前驱(可能是header)——调用者可通过valid()判断成功与否
 }

2.16插入排序

//插入排序
 template <typename T> //对列表中起始于位置p、宽度为n的区间做插入排序
 void List<T>::insertionSort(ListNodePosi<T> p, int n) { //valid(p) && rank(p) + n <= size
     for (int r = 0; r < n; r++) { //逐一为各节点
         insert(search(p->data, r, p), p->data); //查找适当的位置并插入
         p = p->succ; remove(p->pred); //转向下一节点
     }
 }

2.17最大值

//找出在列表中的最大值
 template <typename T> //从起始于位置p的n个元素中选出最大者
 ListNodePosi<T> List<T>::selectMax(ListNodePosi<T> p, int n) {
     ListNodePosi<T> max = p; //最大者暂定为首节点p
     while (  0 < n--) {//从首节点p出发,将后续节点逐一与max比较
         if (max->data <= p->data) max = p;//更新最大元素位置记录
         p = p->succ;//向后移动指针
     }
     return max; //返回最大节点位置
 }

2.18交换

 template <class T> void swap(T& x, T& y)
 {
     T tmp = x;
     x = y;
     y = tmp;
 }

2.19选择排序

 //选择排序
 template <typename T> //对列表中起始于位置p、宽度为n的区间做选择排序
 void List<T>::selectionSort(ListNodePosi<T> p, int n) { //valid(p) && rank(p) + n <= size
  
     ListNodePosi<T> head = header, tail = trailer; //待排序区间为(head, tail)
     while (1 < n) { //在至少还剩两个节点之前,在待排序区间内
         ListNodePosi<T> max = selectMax(head->succ, n); //找出最大者(歧义时后者优先)
         //这里要特别注意,因为有可能存在节点会插入到头哨兵节点之后形成新的首节点,导致
         //p的指针出现问题,所以不能在原始的区间上继续找最大节点,此处使用哨兵的后继指针,
         //用来保证指针的正确性
         //将其移至无序区间末尾(作为有序区间新的首元素)
         if(tail->pred != max)
         swap(tail->pred->data,max->data);// insert(remove(max), tail);
         //插入与删除中存在new 和 delete 这些操作比一般的操作多出两个数量级
         tail = tail->pred; n--;
     }
 }

2.20归并排序

//归并排序
 template<typename T>//列表的归并排序算法:对起始于位置p的n个元素排
 void List<T>::mergeSort(ListNodePosi<T> &p,int n) {//valid(p) && rank(p) + n <= size
     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); //前、后子列表各分别排序
     p= merge(p,m,*this,q,n-m);//归并函数
 }//注意:排序后,p依然指向归并后区间的(新)起点
 

 //归并函数
 template <typename T> //有序列表的归并:当前列表中自p起的n个元素,与列表L中自q起的m个元素归并
 ListNodePosi<T> List<T>::merge(ListNodePosi<T> &p, int n, List<T>& L, ListNodePosi<T>& q, int m) {
     // assert:  this.valid(p) && rank(p) + n <= size && this.sorted(p, n)
     //          L.valid(q) && rank(q) + m <= L._size && L.sorted(q, m)
     // 注意:在被mergeSort()调用时,this == &L && rank(p) + n = rank(q)
     ListNodePosi<T> pp = p->pred; //归并之后p可能不再指向首节点,故需先记忆,以便在返回前更新
     while ((0 < m) && (q != p)) //q尚未出界(或在mergeSort()中,p亦尚未出界)之前
         if ((0 < n) && (p->data <= q->data)) //若p尚未出界且v(p) <= v(q),则
         {
             p = p->succ; n--;
         } //p直接后移,即完成归入
         else //否则,将q转移至p之前,以完成归入
         {
             q = q->succ;
             insert(remove(q ->pred),p);
             m--;
         }
     return pp->succ; //更新的首节点
 }

2.21去重(有序)

template<typename T> int List<T>::uniquify() {
     if (_size < 2) return 0;//就一个节点
     int oldSize = _size;//记录原规模
     ListNodePosi<T> p = header; ListNodePosi<T> q;//p为起点,q为p的后继
     while (trailer != (q=p->succ))
     {
         if (p->data != q->data) p = q;//若互异,转入下一节点
         else remove(q);//删除雷同的后者
     }
     return oldSize - _size;//被删的元素总数
 }

2.22递增减半

//递增类对象
 template<typename T> struct Increase{
     virtual void operator ()(T& e) { e++; }//T可直接递增或已经重载了++
 };
 //递增函数
 template<typename T> void increase(List<T>& L) {
     L.traverse(Increase<T>());//遍历递增
 }
 //减半类对象
 template<typename T> struct Half {
     virtual void operator ()(T& e) { e >>= 1; }
 };
 //减半函数
 template<typename T> void half(List<T>& L) {
     L.traverse(Half<T>());//遍历减半
 }

3.主函数

#include<iostream>
#include "List.h"
using namespace std;

using T = int;

int main() {
	List<T> L;
	L.insertAsFirst(3);//头插法
	//L.Print();//打印列表
	L.disordered();
	L.insertAsLast(2);//尾插入
	L.Print();//打印列表
	ListNodePosi<T> p=L.find(3);
	L.insert(0,p);
	L.Print();//打印列表
	L.insert(p, 5);
	L.Print();
	ListNodePosi<T> q = p->succ;
	L.insert(q, 5);
	L.insert(p, 4);
	L.insert(p, 4);
	L.insert(p, 6);
	L.Print();//打印列表
	cout << "删除节点p:" << endl;
	L.remove(p);//删除p
	L.Print();//打印列表
	L.insert(q, 5);//在q之后插入5
	L.insert(8, q);//在q之前插入8
	L.insert(4, q);//在q之前插入4
	L.Print();//打印列表
	cout << "去重后:" << endl;
	L.deduplicate();//唯一化,去重
	L.Print();
	L.disordered();//逆序对
	ListNodePosi<T> w = L.first();
	L.insert(4, w);//在q之前插入4
	L.insert(w, 9);//在w之后插入9
	L.insert(w,0);//在w之前插入0
	L.Print();
	L.disordered();
	ListNodePosi<T> h= L.first();
	cout << endl;
	L.sort(h,L.size());
	L.uniquify();
	L.Print();
	system("pause");

	return 0;

}

4.运行结果截图

 以上所有代码参考邓俊辉老师的《c++语言版数据结构》,邓老师的数据结构真的太好了!

猜你喜欢

转载自blog.csdn.net/qq_58240448/article/details/126958586