列表(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 ); //整体复制列表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操作(函数对象,可全局性修改)
}; //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 <= size
   for ( 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; //最大者暂定为首节点p
   for ( 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 <= size
   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--;
   }
}

  • 归并排序

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

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依然指向归并后区间的(新)起点

猜你喜欢

转载自blog.csdn.net/weixin_48033173/article/details/113035785
今日推荐