数据结构-C++实现的简单List

本文实现了一个简单的List数据结构,其中包括List的基本的功能&选择排序插入排序…请大家自取好吧
实现的代码和思路都是源于清华数据结构
大家不妨也自己实现一个List

listNode.h

//
// Created on 2022/1/22.
//

#ifndef LIST_LISTNODE_H
#define LIST_LISTNODE_H


typedef int Rank;
#define ListNodePosi(T) ListNode<T>*  //列表结点位置

template <typename T> struct ListNode {         //列表结点的模板类T属于是结点?
    T data;
    ListNodePosi(T) pred; ListNodePosi(T) succ;     //前驱结点和后继结点

    ListNode(){};
    ListNode(T e, ListNodePosi(T) p = nullptr, ListNodePosi(T) s = nullptr)
        :data(e), pred(p), succ(s) {}

    ListNodePosi(T) insertAsPred (T const &e);

    ListNodePosi(T) insertAsSucc (T const &e);
};

template<typename T>
ListNodePosi(T) ListNode<T>::insertAsPred (T const&e ) {
    ListNodePosi(T) x = new ListNode (e, pred, this);       //新建的结点的前驱结点就是this的前驱,后继就是this,因此这就是this的前驱节点了
    this->pred->succ = x;
    this->pred = x;
    return x;
}


template <typename T>
ListNodePosi(T) ListNode<T>::insertAsSucc (T const & e) {
    ListNodePosi(T) x = new ListNode(e, this, this->succ);
    succ->pre = x; succ = x;
    return x;
}



#endif //LIST_LISTNODE_H

list.h

//
// Created on 2022/1/22.
//

#include "listNode.h"
#ifndef LIST_LIST_H
#define LIST_LIST_H


template <typename T> class List {      //列表的模板类
private:
    int _size;
    ListNodePosi(T) header;
    ListNodePosi(T) trailer;            //规模,头哨兵结点,尾哨兵结点
protected:
    void init();        //列表创建时候的初始化
    void clear();
    //复制列表中自位置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个节点基数排序
    void copyNodes ( 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 ); } //将头、尾节点等同于NULL
    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) 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操作(函数对象,可全局性修改)


};

template <typename T> void List<T>::init() {        //列表的初始化
    header = new ListNode<T>;       //创建头部的哨兵结点
    trailer = new ListNode<T>;
    header->succ = trailer; header->pred = nullptr;
    trailer->pred = header; trailer->succ = nullptr;
    _size = 0;      //没有规模
}

//在前面插入一个结点
template <typename T> ListNodePosi(T) List<T>::insertB(ListNodePosi(T) p, T const & e) {
    //insertBefore
    _size ++;
    return p->insertAsPred(e);          //把e当做前驱结点进行插入
}

//在后面插入节点
template <typename T> ListNodePosi(T) List<T>::insertA(ListNodePosi(T) p, T const & e) {
    //insertAfter
    _size ++;
    return p->insertAsSucc;
}
//在最后面插入节点
template <typename T> ListNodePosi(T) List<T>::insertAsLast(T const & e) {
    //将e作为末尾结点插入到list最后面
    _size ++;
    return trailer->insertAsPred(e);
}
//在最前面插入结点
template <typename T> ListNodePosi(T) List<T>::insertAsFirst(T const & e) {
    _size++;
    return header->insertAsSucc;
}

//用一个链表初始化另外一个链表,从结点p开始复制n位
template <typename T>
void List<T>::copyNodes(ListNodePosi(T) p, int n) {
    init();         //this->init()
    while (n--) {
        insertAsLast(p -> data);
        p = p -> succ;      //p指针向后移动
    }
}

template <typename T>
ListNodePosi(T) List<T>::find(const T & e, int n, ListNodePosi(T) p) const {        //在n个前驱节点中进行查找是否有匹配结点p的结点
    while (n--) {
        if (e == (p = p -> pred) -> data) return p;
    }
    return NULL;        //查找失败,返回空指针
}

template <typename T>
int List<T>::deduplicate() {        //无序去重,返回去掉的重复元素的个数
    int old_size = _size;
    if (old_size < 2) return 0;     //至少数量是2才能去重
    //基本的思路是查找第r个数前面是否是有和他重复的结点,如果有就去除掉前面重复的,然后curnode 指向下一个继续去重
    ListNodePosi(T) p = first();        //首结点开始
    Rank index = 1;                     //index用于find函数中的n,就是查找前面n个结点
    while (p = (p -> succ) != trailer) {
        ListNodePosi(T) node = find(p->data, index, p);
        node ? remove(node) : index++;          //如果查到重复的节点了就删除,否则index自加
    }
    return old_size - _size;
}

template <typename T>
int List<T>::uniquify() {       //有序列表的唯一化
    if (_size < 2) return 0;
    int old_size = _size;
    ListNodePosi(T) p = first();            //p用于确定最终的所有的结点:p指向的一定是最终保留的结点
    ListNodePosi(T) node = p -> succ;       //node是用于移动和确定移除的结点
    while (trailer != (node = p -> succ)) {
        node -> data == p -> data ? remove(node) : p = node;
    }
    return old_size - _size;
}
template <typename T>
ListNodePosi(T) List<T>::search(const T & e, int n, ListNodePosi(T) p) const{               //同find类似,在前n个前驱结点中查找不大于p的结点
    ListNodePosi(T) node = p -> pred;
    while (n --) {
        if ((p = p -> pred) -> data <= e) break;
    }
    return p;
}

template <typename T>
ListNodePosi(T) List<T>::selectMax(ListNodePosi(T) p, int n) {      //查找从结点p开始的后面n个节点中,最大的节点
    ListNodePosi(T) maxNode = p;
    ListNodePosi(T) curNode = p;
    while (n > 1) {
        if ((curNode = curNode -> succ) -> data >= maxNode -> data) maxNode = curNode;
    }
    return maxNode;
}

template<typename T>
void List<T>::selectionSort(ListNodePosi(T) p, int n) {
    //从p开始向后n个结点进行选择排序
    ListNodePosi(T) head = p -> pred;       //排序的区间(head, tail) ,全部都是开区间
    ListNodePosi(T) tail = p;
    for (int i = 0; i < n; ++i) tail = tail->succ;      //末尾哨兵结点,开区间,取不到tail  : (head, tail)
    while (n > 1) {
        //注意理解这一个函数(一定要明确区间的范围是什么,一直在变化的),首先选出待排区间的最大值,在原位置删除掉然后插入到待排区间末尾(那就是哨兵tail的前面了)
        insertB(tail, remove(selectMax(head -> succ,n)));
        tail = tail -> pred;        //待排区间收缩,哨兵前移
        n--;        //进行n - 1次的排列就行
    }
}


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++ ) { //逐一为各节点
        insertA ( search ( p->data, r, p ), p->data ); //查找适当的位置并插入
        p = p->succ; remove ( p->pred ); //转向下一节点
    }
}

//将结点p从List中删除掉,并且返回结点的内容
template <typename T>
T List<T>::remove(ListNodePosi(T) p) {
    T value = p -> data;
    p -> pred -> succ = p -> succ;
    p -> succ -> pred = p -> pred;
    delete p;
    _size --;
    return value ;
}


//清除List列表中除了哨兵结点的内容
template <typename T>
void List<T>::clear() {
    while (_size) remove(header -> succ);       //反复删除首结点(哨兵的下一个,直到_size == 0)
}

//析构函数
template <typename T> List<T>::~List<T>() {
    clear();        //清空列表的内容
    delete header;delete trailer;       //释放头结点,尾结点
}


#endif //LIST_LIST_H

main.cpp

#include <iostream>
#include "list.h"

int main() {
    std::cout << "Hello, World!" << std::endl;
    std::cout << "大家自行调用接口调试好吧:)\n" << std::endl;
    List<int> l;
    l.insertAsLast(5);
    l.insertAsLast(6);
    l.insertAsLast(2);
    l.insertAsLast(3);
    l.insertAsLast(9);
    std::cout << "容量是: " << l.size() << std::endl;
   /* List<int> l2;
    ListNodePosi(int) point = l.header -> succ;
    l2.copyNodes(point,3);
    std::cout << "l2的容量是:" << l2.size() << std::endl;*/
    return 0;
}

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值