列表(ListNode)
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)相关推荐
- 如何在JavaScript中实现链接列表
If you are learning data structures, a linked list is one data structure you should know. If you do ...
- 14.相同的树另一棵树的子树检查子树二叉树中的列表(教你们使用相同的套路快速解决这四道题)
一.相同的树 这道题是开胃菜的开始,使用递归进行解决 递归三部曲: 确定递归函数的参数和返回值 因为我们要比较的是两棵树是否相等,所以参数分别是两棵树的根节点,返回值为boolean类型,即两棵树是否 ...
- leetcode算法题--二叉树中的列表★
原题链接:https://leetcode-cn.com/problems/linked-list-in-binary-tree/ 嵌套递归 bool isSubPath(ListNode* head ...
- 【数据结构-查找】3.散列表详解
散列表的一些基本概念 散列表(Hash table,也叫哈希表),是根据关键码值(Key value)而直接进行访问的数据结构.也就是说,它通过把关键码值映射到表中一个位置来访问记录,以加快查找的速度 ...
- C语言将两个数字相加,然后将和作为链接列表返回(附完整源码)
C语言将两个数字相加,然后将和作为链接列表返回 C语言将两个数字相加,然后将和作为链接列表返回完整源码(定义,实现,main函数测试) C语言将两个数字相加,然后将和作为链接列表返回完整源码(定义,实 ...
- 「Leetcode-Python」python中利用链表计算两个非负整数之和(链表类型非列表)
LeetCode里的一个题,没注意到输入类型是列表格式,所以用类结点形式的链表写出来了,做个记录 class ListNode:def __init__(self, x):self.val = xse ...
- Redis 数据结构 :SDS、链表、字典、跳表、整数集合、压缩列表
文章目录 SDS 结构分析 内存策略 空间预分配 惰性空间释放 总结 链表 结构分析 总结 字典 结构分析 rehash 渐进式rehash 总结 跳表 结构分析 总结 整数集合 结构分析 升级 降级 ...
- 获取用户列表为空_数据结构和算法(Golang实现)(15)常见数据结构-列表
列表 一.列表 List 我们又经常听到 列表 List 数据结构,其实这只是更宏观的统称,表示存放数据的队列. 列表 List:存放数据,数据按顺序排列,可以依次入队和出队,有序号关系,可以取出某序 ...
- 列表反向组成数字相加,并输出数组反向组成列表
# Definition for singly-linked list. #在节点ListNode定义中,定义为节点为结构变量. #节点存储了两个变量:value 和 next.value 是这个节点 ...
最新文章
- 点分十进制IP校验、转换,掩码校验
- 新生男婴自带新冠抗体,感染者母亲如今抗体消失,医生:抗体转移了
- 全球及中国生物柴油行业产量规模及市场消费需求预测报告2021-2027年
- 在linux系统JDK安装中文字体
- 【转】WPF PRISM开发入门一( 初始化PRISM WPF程序)
- DBA的宿命(困兽之斗)
- [转载] C++子字符串查找及提取
- 磁盘位置_ORACLE RAC ASM磁盘组迁移到新的ASM磁盘组方法
- CSA FT1、FT2、FT4、FT5 和 FT6
- 使用ETest实现汽车ECU的HIL测试
- jdk证书的相关命令
- 邮箱邮件安全问题有哪些?如何做邮件安全宣传?
- 【云学习笔记】二、免费云服务器与免费域名组合打造自己的个人空间
- 做数据分析的36款常用工具!!!初学者必备,纯干货!!
- 【论文解读】持续学习三种情形
- 墨海醉笔,又流逝了多少华年?
- 愚人节的幽默感,我只服阿里云......
- Android下载管理问题分析
- 立创元件导入AD集成库的方法
- cd命令回到上级目录和回到根目录