本文使用c++实现list数据结构,list的接口函数采用高效的实现方式,这样一方面使我加深对数据结构的理解,另一方便可以让我再复习复习c++,通过前几天写的vector数据结构的底层实现,我确实又进一步地熟悉使用C++进行编程,,这次写list的实现过程中,我几乎没有怎么查看《c++prime》了哈哈,就是函数对象形式的遍历函数的声明格式怎么也想不起来,后来查书才明白函数的形参其实是个类的对象,只不过这个类名要在声明前指明,如下:
template
list的实现包含两个类:listNode和list,其中listNode中主要描述了list中单个节点的内部结构,包含一个data变量和两个分别指向前节点和后节点的指针;而list类则是描述了一个list的结构及其操作,比如查看规模大小、插入新节点、删除节点、排序、查找等。
操作 | 功能 | 对象 |
listNode() | 默认构造函数 | |
listNode(T e, listNode |
构造函数,设置data,指向前后节点的指针 | |
~listNode | 析构函数 | |
insertAsPred(const T& e) | 在当前节点前插入一个新节点 | 节点 |
insertAsSucc(const T& e) | 在当前节点后插入一个新节点 | 节点 |
操作 | 功能 | 对象 |
list() | 默认构造函数,只初始化list的首尾哨兵节点 | |
list(std::initializer_list |
构造函数(列表初始化方式) | |
list(listNode |
构造函数,拷贝指定节点及其后n个节点 | |
list(list |
构造函数,拷贝另一list对象 | |
list(list |
构造函数,拷贝另一list对象的指定区间 | |
~list() | 析构函数,手动释放哨兵及有效节点的内存空间 | |
init() | list初始化时创建前后哨兵节点 | 列表 |
size() | 返回list对象的规模 | 列表 |
display() | 打印当前list中的所有元素 | 列表 |
first() | 返回第一个有效节点的地址 | 列表 |
last() | 返回最后一个有效节点的地址 | 列表 |
find(const T& e, int n, listNode |
在节点p之前的n个长度范围内查找元素 | 列表 |
find(const T& e) | 在整个list中查找元素 | 列表 |
search(const T& e, int n, listNode |
在节点p之前的n个长度范围内查找元素e,返回不大于此元素的最大节点的地址 | 有序列表 |
search(const T& e) | 在整个list中查找元素,返回不大于此元素的最大节点的地址 | 有序列表 |
insertAsFirst(const T& e) | 插入元素作为first节点 | 列表 |
insertAsLast(const T& e) | 插入元素作为last节点 | 列表 |
insertAsPred(listNode |
在节点P之前插入元素e | 列表 |
insertAsSucc(listNode |
在节点P之后插入元素e | 列表 |
insert(Rank r, const T& e) | 在指定秩出插入元素(警告:线性复杂度) | 列表 |
remove(listNode |
删除指定节点 | 列表 |
clear() | 清除list内所有有效节点 | 列表 |
deduplicate() | 去除list内重复元素 | 列表 |
uniquify() | 去除list内重复元素 | 有序列表 |
traverse(void(*func)(T &)) | 批量处理list内所有元素(函数指针方式) | 列表 |
traverse(FuncClass func) | 批量处理list内所有元素(函数对象方式) | 列表 |
sort(listNode |
排序接口汇总 | 列表 |
insertionSort() | 插入排序法 | 列表 |
insertionSort(listNode |
对从p节点开始的n范围内的节点进行排序(插入排序法) | 列表 |
selectionSort() | 选择排序法 | 列表 |
selectionSort(listNode |
对从p节点开始的n范围内的节点进行排序(选择排序法) | 列表 |
mergeSort(listNode |
对从p节点开始的n范围内的节点进行排序(归并排序法) | 列表 |
重载运算符[] | 下标运算符 | 列表 |
重载运算符= | 赋值运算符(列表赋值方式) | 列表 |
(1) listNode.h
#pragma once
typedef int Rank;
template struct listNode //节点元素模板类
{
//成员变量
T data;
listNode *pred, *succ; //定义前驱和后继指针,实现双向链表
//构造函数
listNode() {} //构造list前后哨兵节点用
listNode(T e, listNode *p = nullptr, listNode *s = nullptr) :data(e), pred(p), succ(s) {}
//析构函数
~listNode(){}
//成员函数
listNode* insertAsPred(const T& e); //在当前节点前插入一个新节点
listNode* insertAsSucc(const T& e); //在当前节点后插入一个新节点
};
template listNode* listNode::insertAsPred(const T& e)
{
listNode *p = new listNode(e, pred, this); //更新4个指针的指向
pred->succ = p;
pred = p;
return p;
}
template listNode* listNode::insertAsSucc(const T& e)
{
listNode *p = new listNode(e, this, succ);
succ->pred = p;
succ = p;
return p;
}
(2) list.h
#pragma once
#include "listNode.h"
typedef int Rank;
template class list //list结构: [sentinel node]--[[first]...[]....[last]]--[sentinel node]
{
protected:
int _size; //list规模
listNode *header, *trailer; //list的前后哨兵节点的指针
public:
//构造函数
list() { init(); }
list(std::initializer_list li); //列表初始化构造方式
list(listNode* p, int n); //拷贝构造,拷贝节点p及其后n个范围内的所有节点
list(list& li) :list(li.header, li._size) {} //拷贝构造,拷贝整个list对象
list(list& li, Rank lr, Rank rr); //拷贝构造,拷贝指定list对象的指定区间
//析构函数(只需要手动处理new的对象)
~list();
//普通成员函数
void init(); //list初始化时创建前后哨兵节点,_size置0
int size(); //返回list对象的规模
void display(); //打印当前list中的所有元素
listNode* first(); //返回第一个有效节点的地址
listNode* last(); //返回最后一个有效节点的地址
listNode* find(const T& e, int n, listNode* p); //在节点p之前的n个长度范围内查找元素e
listNode* find(const T& e); //查找元素e
listNode* search(const T& e, int n, listNode* p); //在节点p之前的n个长度范围内查找元素e(要求list为有序序列,返回不大于此元素的最大节点的指针)
listNode* search(const T& e); //查找元素e(要求list为有序序列,返回不大于此元素的最大节点的指针)
listNode* insertAsFirst(const T& e); //插入元素作为first节点
listNode* insertAsLast(const T& e); //插入元素作为last节点
listNode* insertAsPred(listNode* p, const T& e); //在节点P之前插入元素e
listNode* insertAsSucc(listNode* p, const T& e); //在节点P之后插入元素e
listNode* insert(Rank r, const T& e); //在指定秩出插入元素(警告:线性复杂度)
T remove(listNode* p); //删除指定节点
int clear(); //清除list内所有有效节点
int deduplicate(); //去除list内重复元素
int uniquify(); //去除list内重复元素(要求list为有序序列)
void traverse(void(*func)(T &)); //批量处理list内所有元素(函数指针方式)
template void traverse(FuncClass func); //批量处理list内所有元素(函数对象方式)
void sort(listNode* p, int n,int s); //排序接口汇总
void insertionSort(); //插入排序法
void insertionSort(listNode* p,int n); //对从p节点开始的n范围内的节点进行排序
void selectionSort(); //选择排序法
void selectionSort(listNode* p, int n); //对从p节点开始的n范围内的节点进行排序
void mergeSort(listNode* p,int n); //归并排序法
//重载运算符
T& operator[](Rank r); //下标运算符重载
list& operator=(const list& li); //赋值运算符重载
};
template void list::init()
{
header = new listNode(); //创建前后哨兵节点
trailer = new listNode();
_size = 0;
header->succ = trailer; //设置指针指向
header->pred = nullptr;
trailer->pred = header;
trailer->succ = nullptr;
}
template list::list(std::initializer_list li)
{
init();
listNode *p=header;
for (auto iter = li.begin(); iter != li.end(); iter++)
{
p = p->insertAsSucc(*iter);
_size++;
}
}
template list::list(listNode* p, int n)
{
init();
listNode *ptr=header;
while (n--)
{
ptr=ptr->insertAsSucc(p->data);
p = p->succ;
_size++;
}
}
template list::list(list& li, Rank lr, Rank rr)
{
init();
listNode* p = li.first();
listNode* ptr = header;
for (int i = 0; i < rr; i++)
{
if (i < lr)
p = p->succ;
else
{
ptr = ptr->insertAsSucc(p->data);
p = p->succ;
_size++;
}
}
}
template list::~list()
{
clear(); //清除所有有效节点
delete header;
delete trailer;
}
template void list::display()
{
listNode* p = header;
cout << "size:" << _size << endl;
if (_size)
{
for (Rank r = 0; r < _size; r++)
{
p = p->succ;
(r < (_size - 1)) ? cout << p->data << "," : cout << p->data;
}
cout << endl;
}
}
template int list::size()
{
return _size;
}
template listNode* list::find(const T& e, int n, listNode* p) //包含p节点,n>1才能搜索
{
while ((n--)&&(p!=header)) //已经遍历n次或则到达header
{
if (p->data == e)
return p;
else
p = p->pred;
}
return nullptr;
}
template listNode* list::find(const T& e)
{
return find(e, _size - 1, last());
}
template listNode* list::search(const T& e, int n, listNode* p) //包含p节点,n>1才能搜索
{
while ((n--) && (p != header))
{
if (p->data <= e) //返回不大于指定元素的最大节点,方便在其后面插入
return p;
else
p = p->pred;
}
return p;
}
template listNode* list::search(const T& e)
{
return search(e, _size + 1, last());
}
template listNode* list::first()
{
return header->succ;
}
template listNode* list::last()
{
return trailer->pred;
}
template T& list::operator[](Rank r)
{
listNode* p=header->succ;
while (r-->0)
{
p = p->succ;
}
return p->data;
}
template listNode* list::insertAsFirst(const T& e)
{
_size++;
listNode *p = header->insertAsSucc(e); //函数内部已经更新了4个指针指向
return p;
}
template listNode* list::insertAsLast(const T& e)
{
_size++;
listNode *p = trailer->insertAsPred(e);
return p;
}
template listNode* list::insertAsPred(listNode* p, const T& e)
{
_size++;
return p->insertAsPred(e);
}
template listNode* list::insertAsSucc(listNode* p, const T& e)
{
_size++;
return p->insertAsSucc(e);
}
template listNode* list::insert(Rank r, const T& e)
{
listNode *p=header;
while (r--)
{
p = p->succ;
}
return insertAsSucc(p, e);
}
template T list::remove(listNode* p)
{
T e = p->data;
p->pred->succ = p->succ;
p->succ->pred = p->pred;
_size--;
delete p;
return e;
}
template int list::clear()
{
int oldSize = _size;
while (header->succ != trailer)
remove(header->succ);
return oldSize;
}
template int list::deduplicate()
{
if (!_size) return 0;
int n = 0;
listNode* p = header->succ;
listNode* lp; //缓存p的前一个元素
for (int i = 0; i < _size;)
{
lp = p->pred;
if (find(p->data, _size, p->pred)) //在当前元素之前寻找,越界则退出
{
remove(p);n++;
p = lp->succ;
}
else
{
i++;
p = p->succ;
}
}
return n;
}
template int list::uniquify()
{
if (!_size) return 0;
int oldSize = _size;
listNode *p = header->succ;
while (p->succ!=trailer) //队尾越界停止
{
if (p->data == p->succ->data)
remove(p->succ);
else
p = p->succ;
}
return oldSize - _size;
}
template void list::traverse(void(*func)(T &))
{
for (Rank r = 0; r < _size; r++)
func((*this)[r]);
}
template template void list::traverse(FuncClass func)
{
for (Rank r = 0; r < _size; r++)
func((*this)[r]);
}
template list& list::operator=(const list &li)
{
clear(); //清空有效节点
if (!li._size) return *this;
listNode* p = li.header;
listNode* lp = header;
while ((p = p->succ) != li.trailer)
{
lp->insertAsSucc(p->data);
lp = lp->succ;
_size++;
}
return *this;
}
template void list::sort(listNode* p, int n, int s)
{
switch (s)
{
case 0:
insertionSort(p, n); break;
case 1:
selectionSort(p, n); break;
case 2:
mergeSort(p, n); break;
default:
break;
}
}
template void list::insertionSort()
{
if (_size < 2) return;
listNode *p = header->succ;
while (p != trailer) //列尾溢出则终止
{
search(p->data, _size+1, p->pred)->insertAsSucc(p->data);
_size++;
p = p->succ;
remove(p->pred);
}
}
template void list::insertionSort(listNode* p, int n)
{
if (n < 2) return;
int s = 0;
while ((n--) && (p != trailer)) //变量n次或列尾溢出则终止
{
search(p->data, s, p->pred)->insertAsSucc(p->data);
_size++;
p = p->succ;
remove(p->pred);
s++;
}
}
template void list::selectionSort()
{
if (_size < 2) return;
listNode *p = first();
listNode *ptr; //缓存待删除的节点指针
for (int i = 0; i < _size; i++) //_size次迭代
{
T min = first()->data;
p = first();
ptr = p;
for (int j = 0; j < _size - i; j++) //内循环找最小值并插入到last位置(保证排序稳定)
{
if ((p->data) <= min)
{
min = p->data;
ptr = p;
}
p = p->succ;
}
remove(ptr);
insertAsLast(min);
}
}
template void list::selectionSort(listNode* p, int n)
{
if (n < 2) return;
p = p->pred;
listNode *pp = p->succ; //迭代指针
listNode *ptr; //缓存待删除的节点指针
listNode *trail = p; //排序区间的最后一个元素,即排序区间为(p->pred,trail)
for (int i = 0; i < n+1; i++)
trail = trail->succ;
for (int i = 0; i < n; i++) //n次迭代
{
T min = (p->succ)->data;
pp = p->succ;
ptr = p->succ;
for (int j = 0; j < n - i; j++) //内循环找最小值并插入到trail位置(保证排序稳定)
{
if ((pp->data) <= min)
{
min = pp->data;
ptr = pp;
}
pp = pp->succ;
}
remove(ptr);
trail->insertAsPred(min);
_size++;
}
}
template void list::mergeSort(listNode* p, int n) //[p,p_n)
{
if (n < 2) return;
//开始分裂
listNode* ppred = p->pred; //缓存待排序list的前哨兵
listNode* pmi = p; //计算中间节点
for (int i = 0; i < (n >> 1); i++) //[p0,p1,p2] n=3 ==> [p0] [p1,p2]
{
pmi = pmi->succ;
}
mergeSort(p, n >> 1); //这两句递归语句表示已分离的两个子序列均已经排序完成
mergeSort(pmi, n - (n >> 1));
//开始归并(两个有序短序列==》一个有序长序列) [pred][AAAAAAAAA][BBBBBBBBB]
//更新各端点的地址(在递归时插入和删除改变了逻辑顺序节点的实际物理地址)
p = ppred->succ;
pmi = p; //计算中间节点
for (int i = 0; i < (n >> 1); i++)
{
pmi = pmi->succ;
}
for (Rank i = (n >> 1), j = (n - (n >> 1)); i || j;)
{
if ((i > 0) && (j == 0)) //只剩下前段list
{
i--;
ppred->insertAsSucc(p->data);
ppred = ppred->succ;
_size++;
p = p->succ;
remove(p->pred);
}
if ((j > 0) && (i == 0)) //只剩下后段list
{
j--;
ppred->insertAsSucc(pmi->data);
ppred = ppred->succ;
_size++;
pmi = pmi->succ;
remove(pmi->pred);
}
if ((i > 0) && (j > 0)) //两段list都有值,则选择最小的插在前面
{
if ((p->data) < (pmi->data))
{
i--;
ppred->insertAsSucc(p->data);
ppred = ppred->succ;
_size++;
p = p->succ;
remove(p->pred);
}
else
{
j--;
ppred->insertAsSucc(pmi->data);
ppred = ppred->succ;
_size++;
pmi = pmi->succ;
remove(pmi->pred);
}
}
}
}