【二】数据结构之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)<_sizedo{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等数据结构的具体应用。

【二】数据结构之List相关推荐

  1. 大二数据结构实验(迪杰斯特拉最短路径)

    大二数据结构实验,有详细批注,代码可以直接运行,希望可以给大家提供到帮助. 实验目的 掌握图的邻接矩阵的存储定义. 掌握图的最短路径(Dijsktra)算法的实现. 实验内容 设计校园平面图,所含景点 ...

  2. 把数据转换为在内存中Tree(树形结构)。_Linux的中断处理机制 [二] - 数据结构(2)...

    Linux的中断处理机制 [一] - 数据结构(1) 上文提到,每个IRQ同时有"irq"和"hwirq"两个编号.这里"hwirq"是硬件 ...

  3. php面试题之二——数据结构和算法(高级部分)

    二.数据结构和算法 1.使对象可以像数组一样进行foreach循环,要求属性必须是私有.(Iterator模式的PHP5实现,写一类实现Iterator接口)(腾讯) <?phpclass Te ...

  4. 大二数据结构与算法实习

    大二小学期数据结构与算法实习PTA 12道数据结构题目题解和AC代码 时间:2022.08.15-2022.09.05 网课 第1题 范围查询(Range) 题目大意 数轴上有n个点,对于任一闭区间 ...

  5. JNI实现源码分析【二 数据结构】

    正文 在展开深入讨论之前,先说一下Dalvik中和JNI相关的数据结构,是很有必要的. 在Object.h中定义了很多的数据结构: 0x01: 虚拟机中的对象 我们知道,Java是面向对象的,Java ...

  6. 剑指offer(C++)-JZ34:二叉树中和为某一值的路径(二)(数据结构-树)

    作者:翟天保Steven 版权声明:著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处 题目描述: 输入一颗二叉树的根节点root和一个整数expectNumber,找出二叉树中结点值 ...

  7. 【数据结构】-大二数据结构与算法课程设计实训报告

    采花生问题 1.1 需求分析 1.1.1 题目概要 给一矩阵,按贪心思路最多能采多少花生并在规定时间内返回. 1.1.2 题目要求 给定一块花生田的大小和花生的分布,在限定时间内,小Q最多可以采到多少 ...

  8. 无序链表(顺序查找)和有序数组(二分查找)-基础实现-符号表(二)-数据结构和算法(Java)

    文章目录 1 无序链表的顺序查找 1.1 无序链表实现 1.2 分析 2 有序数组中的二分查找 2.1 实现 2.2 分析 3 对二分查找的分析 4 总结 5 后记 1 无序链表的顺序查找 1.1 无 ...

  9. lru算法C语言结构体指针,BCache源码浅析之二数据结构与操作

    ZZ: http://blog.csdn.net/wanthelping/article/details/50448975 2.主流程与数据结构 2.1 bcache初始化 (1) register_ ...

  10. SPI子系统分析之二:数据结构【转】

    转自:http://www.cnblogs.com/jason-lu/articles/3164901.html 内核版本:3.9.5 spi_master struct spi_master用来描述 ...

最新文章

  1. mac系统下安装、启动、停止mongodb
  2. Linux内核defconfig在哪,Linux内核根目录中的配置文件.config中包含了许多宏定义,...
  3. 给定0~N之间的N个数字(大于等于0,小于N,不重复)进行按小到大排列(不用其它的经典排序算法)
  4. Flink 1.7.2 dataset transformation 示例
  5. VirtualBox 4.3“不能为虚拟电脑 打开一个新任务”解决方案 - 转
  6. Go语言中使用SQLite数据库
  7. html设置等宽字体效果
  8. PR曲线以及ROC曲线的绘制
  9. matlab矩阵最大值最小值均值,Matlab 处理数据—最小值、最大值、均值、方差
  10. 第二门课 改善深层神经网络:超参数调试、正则化以及优化(Improving Deep Neural Networks:Hyperparameter tuning…)
  11. 网页中直接跳转相应页面方法
  12. java 实现橡皮擦_基于canvas剪辑区域功能实现橡皮擦效果
  13. Python 中的 sequence 类型
  14. text-overflow属性的使用
  15. linux下使用VSCode的C++添加json问题。
  16. python元类_Python基础:元类
  17. shell小记:dirname
  18. 缺血性中风和肠道菌群之间的桥梁:短链脂肪酸
  19. AVFoundation开发秘籍笔记-02播放和录制音频
  20. BigBrother的大数据之旅 Day 1 Linux(1)

热门文章

  1. 微信小游戏开发(1)
  2. 使用原始套接字Raw Socket实现数据包嗅探
  3. Flask Web实战-新闻资讯项目
  4. 在微信公众号中如何添加【自定义菜单】,原创图文教程
  5. 一等公民 二等公民_公民如何通过开放式硬件成为科学家
  6. 详细讲解一下Linux内核系统结构(图例解析)
  7. 【LoadingDialog】标准款待加载对话框
  8. 【蓝桥杯真题】18天Python组冲刺 心得总结
  9. 一周快讯:小米路演爆满估值惹争议,百度App回应任命papi酱
  10. CSS 动画相关属性动态实例大全(82种),2023年祝福第二弹(送你一只守护兔)(下),守护兔源代码免费下载