ListNode

列表节点 ADT 支持的操作接口

操作接口 功能
data() 当前节点所存数据对象
pred() 当前节点前驱节点的位置
succ() 当前节点后继节点的位置
insertAsPred(e) 插入前驱节点,存入被引用对象 e,返回新节点位置
insertAsSucc(e) 插入后继节点,存入被引用对象 e,返回新节点的位置

列表 ADT 支持的操作接口

操作接口 功能 适用对象
size() 返回节点总数 列表
first()、last() 返回首、末节点的位置 列表
insertAsFirst(e)、insertAsLast(e) 将 e 当做首、末节点插入 列表
insertA(p, e)、insertB(p, e) 将 e 当做节点 p 的直接后继、前驱插入 列表
remove( p ) 删除位置 p 处的节点,返回其数值 列表
disordered() 判断所有节点是否已按非降序排列 列表
sort() 调整各节点的位置,使之升序 列表
find(e) 查找目标元素 e,失败返回 NULL 列表
search(e) 查找目标元素 e,返回不大于 e 且秩最大的节点的位置 有序列表
deduplicate() 删除重复节点 列表
uniquify() 删除重复节点 有序列表
traverse() 遍历并统一处理所有节点,处理方法由函数对象指定 列表

ListNode 模板类

// listNode.h
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 ); //紧随当前节点之后插入新节点
};

List 模板类

#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项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 ); //整体复制列表LList ( 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 ); } //将头、尾节点等同于NULLListNodePosi(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操作(函数对象,可全局性修改)
}; //List

前插入
详解 insertAsPred(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; //返回新节点的位置
}
  • 插入排序

始终将整个序列视作并切分为两个部分:有序的前缀,无序的后缀;通过迭代,反复地将后缀的首元素转移至前缀中。

template <typename T> //对列表中起始于位置p、宽度为n的区间做插入排序
void List<T>::insertionSort ( ListNodePosi(T) p, int n ) { //valid(p) && rank(p) + n <= sizefor ( int r = 0; r < n; r++ ) { //逐一为各节点insertA ( 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; //最大者暂定为首节点pfor ( ListNodePosi(T) cur = p; 1 < n; n-- ) //从首节点p出发,将后续节点逐一与max比较if ( !lt ( ( cur = cur->succ )->data, max->data ) ) //若当前元素不小于max,则max = cur; //更新最大元素位置记录return max; //返回最大节点位置
}template <typename T> //对列表中起始于位置p、宽度为n的区间做选择排序
void List<T>::selectionSort ( ListNodePosi(T) p, int n ) { //valid(p) && rank(p) + n <= sizeListNodePosi(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--;}
}
  • 归并排序

二路归并,将两个有序序列合并为一个有序序列。

template <typename T> //列表的归并排序算法:对起始于位置p的n个元素排序
void List<T>::mergeSort ( ListNodePosi(T) & p, int n ) { //valid(p) && rank(p) + n <= sizeif ( 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依然指向归并后区间的(新)起点

列表(ListNode)相关推荐

  1. 如何在JavaScript中实现链接列表

    If you are learning data structures, a linked list is one data structure you should know. If you do ...

  2. 14.相同的树另一棵树的子树检查子树二叉树中的列表(教你们使用相同的套路快速解决这四道题)

    一.相同的树 这道题是开胃菜的开始,使用递归进行解决 递归三部曲: 确定递归函数的参数和返回值 因为我们要比较的是两棵树是否相等,所以参数分别是两棵树的根节点,返回值为boolean类型,即两棵树是否 ...

  3. leetcode算法题--二叉树中的列表★

    原题链接:https://leetcode-cn.com/problems/linked-list-in-binary-tree/ 嵌套递归 bool isSubPath(ListNode* head ...

  4. 【数据结构-查找】3.散列表详解

    散列表的一些基本概念 散列表(Hash table,也叫哈希表),是根据关键码值(Key value)而直接进行访问的数据结构.也就是说,它通过把关键码值映射到表中一个位置来访问记录,以加快查找的速度 ...

  5. C语言将两个数字相加,然后将和作为链接列表返回(附完整源码)

    C语言将两个数字相加,然后将和作为链接列表返回 C语言将两个数字相加,然后将和作为链接列表返回完整源码(定义,实现,main函数测试) C语言将两个数字相加,然后将和作为链接列表返回完整源码(定义,实 ...

  6. 「Leetcode-Python」python中利用链表计算两个非负整数之和(链表类型非列表)

    LeetCode里的一个题,没注意到输入类型是列表格式,所以用类结点形式的链表写出来了,做个记录 class ListNode:def __init__(self, x):self.val = xse ...

  7. Redis 数据结构 :SDS、链表、字典、跳表、整数集合、压缩列表

    文章目录 SDS 结构分析 内存策略 空间预分配 惰性空间释放 总结 链表 结构分析 总结 字典 结构分析 rehash 渐进式rehash 总结 跳表 结构分析 总结 整数集合 结构分析 升级 降级 ...

  8. 获取用户列表为空_数据结构和算法(Golang实现)(15)常见数据结构-列表

    列表 一.列表 List 我们又经常听到 列表 List 数据结构,其实这只是更宏观的统称,表示存放数据的队列. 列表 List:存放数据,数据按顺序排列,可以依次入队和出队,有序号关系,可以取出某序 ...

  9. 列表反向组成数字相加,并输出数组反向组成列表

    # Definition for singly-linked list. #在节点ListNode定义中,定义为节点为结构变量. #节点存储了两个变量:value 和 next.value 是这个节点 ...

最新文章

  1. 点分十进制IP校验、转换,掩码校验
  2. 新生男婴自带新冠抗体,感染者母亲如今抗体消失,医生:抗体转移了
  3. 全球及中国生物柴油行业产量规模及市场消费需求预测报告2021-2027年
  4. 在linux系统JDK安装中文字体
  5. 【转】WPF PRISM开发入门一( 初始化PRISM WPF程序)
  6. DBA的宿命(困兽之斗)
  7. [转载] C++子字符串查找及提取
  8. 磁盘位置_ORACLE RAC ASM磁盘组迁移到新的ASM磁盘组方法
  9. CSA FT1、FT2、FT4、FT5 和 FT6
  10. 使用ETest实现汽车ECU的HIL测试
  11. jdk证书的相关命令
  12. 邮箱邮件安全问题有哪些?如何做邮件安全宣传?
  13. 【云学习笔记】二、免费云服务器与免费域名组合打造自己的个人空间
  14. 做数据分析的36款常用工具!!!初学者必备,纯干货!!
  15. 【论文解读】持续学习三种情形
  16. 墨海醉笔,又流逝了多少华年?
  17. 愚人节的幽默感,我只服阿里云......
  18. Android下载管理问题分析
  19. 立创元件导入AD集成库的方法
  20. cd命令回到上级目录和回到根目录

热门文章

  1. ImageList 导出文件
  2. html实现选择头像,HTML5实现上传头像图片大小选择(简单实现)
  3. Unity3D使用Animation编辑器编辑动画
  4. VUE Echarts世界地图 中文名称显示国家
  5. 网络拨测DialTest简单介绍
  6. 三分钟入门大数据之用户画像标签的分类
  7. Android Studio常用快捷键
  8. 中缀向后缀转换表达式
  9. 直播技术总结(三)ijkplayer的一些问题优化记录
  10. 一维元胞自动机生命游戏