C++封装链式表-链表
Posted Zip Zou
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了C++封装链式表-链表相关的知识,希望对你有一定的参考价值。
此文章为上一篇文章续篇
面向对象三大特性:封装、继承、多态。这也是面向对对象语言相对面向过程而言,最大的优势和特点。面向对象使得程序更加利于维护,让设计人员更加关注设计,要想真正的理解面向对象的特性,则必须要清楚和掌握这三大规律。
链式结构分析
对于链式结构而言,与线性结构有所差别的是,其逻辑结构不为连续的,而是采用一种前驱后继的方式进行节点之间的关联,使得上一个节点,可以访问到下一个节点,从而形成一种链式的线性结构。链式结构的优点在于,其插入删除的效率较高,因此叫常用于插入删除较频繁的情形。
对于链式结构,应该有的属性为:
- 链表由节点构成,每一个节点包含一个数据
- 链表为链式结构,在物理上不连续
- 链式结构为随机存储结构,在堆区开辟空间,需要手动管理内存
内存管理请参看:C++内存管理和智能指针
开始链表的实现
- 链表节点的实现
/**
* 链表节点类
*/
template<class T>
class ZLinkedListNode
public:
/**
* 默认构造函数,需要目的类型提供默认构造函数å
*/
ZLinkedListNode<T>()_nextNode = nullptr;
/**
* 构造函数,用于构造一个链表节点,并为其制定一个节点值
* @param data 要赋予的节点的值
*/
ZLinkedListNode<T>(const T &data);
/**
* 构建指定前驱的链表节点
* @param data 要指定节点的值
* @param preNode 要指定的上一个节点
*/
ZLinkedListNode<T>(const T &data, ZLinkedListNode &preNode);
/**
* 获取节点值
* @return 返回该节点值的副本,为保证安全,应该相应的数据类型重载赋值和拷贝构造
*/
const T data() constreturn _data;
/**
* 引用该节点的值
* @return 返回节点值的引用
*/
T &ref() return _data;
/**
* 获取下一个节点
* @return 返回下一个节点
*/
ZLinkedListNode<T> *nextNode()return _nextNode;
/**
* 下一个节点的引用
* @return 返回下一个节点指针的引用
*/
ZLinkedListNode<T> *&nextNodeRef()return _nextNode;
/**
* 设置下一个节点
* @param nextNode 要设置的下一个节点
*/
void setNextNode(ZLinkedListNode<T> *nextNode);
protected:
T _data;// 节点数据
ZLinkedListNode<T> *_nextNode; // 下一个节点
;
/*以下为Node的实现*/
template<class T>
ZLinkedListNode<T>::ZLinkedListNode(const T &data)
_data = data;
_nextNode = nullptr;
template<class T>
ZLinkedListNode<T>::ZLinkedListNode(const T &data, ZLinkedListNode &preNode)
_data = data;
// 连接节点
preNode._nextNode = this;
_nextNode = nullptr;
template<class T>
void ZLinkedListNode<T>::setNextNode(ZLinkedListNode<T> *nextNode)
_nextNode = nextNode;
- 链表的实现
/**
* 链表类
*/
template<class T>
class ZLinkedList : public Sequence<T>
public:
/**
* 默认构造函数,为节省空间,不设置哨兵节点
*/
ZLinkedList<T>();
/**
* 根据指定值创建链表,该值为链表头部
* @param data 要指定的头部值
*/
ZLinkedList<T>(const T& data);
/**
* 创建指定值的指定个数的链表
* @param data 指定值
* @param count 指定值的个数
*/
ZLinkedList<T>(const T& data, z_size count);
/**
* 插入到最后一个位置
*/
virtual void push_back(const T& val);
/**
* 从指定位置中,移除元素,并返回该元素的副本,若为指针,请自行进行内存管理
* @param pos 元素位置
* @return 返回该元素值
*/
virtual T pop(const rank pos);
/**
* 访问指定位置的值
* @param pos 元素所在的位置
* @return 返回该位置的元素值
*/
virtual const T &at(const rank pos) const;
/**
* 移除指定位置元素
* @param pos 元素所在位置
* @return 返回是否移除成功
*/
virtual bool remove(const rank pos);
/**
* 获取迭代器
* @return 返回迭代器
*/
virtual Iterator<T> &iterator();
/**
* 重载访问器
* @param pos 元素位置
* @return 返回元素引用
*/
virtual T& operator[](const rank pos);
/**
* 判断是否为空表
*/
bool isEmpty() const;
virtual ~ZLinkedList();
z_size length() constreturn _length;
//声明友元关系
friend class ZLinkedListIterator<T>;
protected:
ZLinkedListNode<T> *_list_head; // 链表头结点
ZLinkedListNode<T> *_list_tail; // 链表尾节点,冗余数据,为了加快尾插法的效率
z_size _length; // 长度
Iterator<T> *preIterator; // 上一个迭代器,用于迭代器的释放
;
/*
链表的实现
*/
template<class T>
ZTemplate::ZLinkedList<T>::ZLinkedList():Sequence<T>()
_list_head = nullptr;
_length = 0;
_list_tail = nullptr;
preIterator = nullptr;
template<class T>
ZTemplate::ZLinkedList<T>::ZLinkedList(const T &data):Sequence<T>()
_list_head = new ZTemplate::ZLinkedListNode<T>(data);
_length = 1;
preIterator = nullptr;
_list_tail = _list_head;
template<class T>
ZTemplate::ZLinkedList<T>::ZLinkedList(const T &data, ZTemplate::z_size count):Sequence<T>()
_list_head = new ZTemplate::ZLinkedListNode<T>(data);
_length = count;
preIterator = nullptr;
ZTemplate::ZLinkedListNode<T> *curNode = _list_head; // 用于拼接节点
for (int i = 0; i < count - 1; i++)
ZTemplate::ZLinkedListNode<T> *newNode = new ZTemplate::ZLinkedListNode<T>(data, *curNode); // 在构建时,直接追加至末尾
curNode = newNode;
_list_tail = curNode;
template<class T>
void ZTemplate::ZLinkedList<T>::push_back(const T &val)
// 创建节点,直接插入尾部
++_length;
if (_list_head == nullptr) // 头为空
_list_head = _list_tail = new ZLinkedListNode<T>(val);
else
_list_tail = new ZTemplate::ZLinkedListNode<T>(val, *_list_tail);
template<class T>
T ZTemplate::ZLinkedList<T>::pop(const rank pos)
// 节点游标
ZTemplate::ZLinkedListNode<T> *nodePointer = _list_head;
for (int i = 0; i < pos; i++)
nodePointer = nodePointer->nextNode();
return nodePointer->data();
template<class T>
const T& ZTemplate::ZLinkedList<T>::at(const rank pos) const
// 节点游标
ZTemplate::ZLinkedListNode<T> *nodePointer = _list_head;
for (int i = 0; i < pos; i++)
nodePointer = nodePointer->nextNode();
return nodePointer->ref();
template<class T>
bool ZTemplate::ZLinkedList<T>::remove(const rank pos)
if (pos >= _length)
return false;
--_length;
// 头结点删除
if (0 == pos)
ZTemplate::ZLinkedListNode<T> *delNode = _list_head;
_list_head = _list_head->nextNode();
delete delNode;
return true;
// 节点游标
ZTemplate::ZLinkedListNode<T> *nodePointer = _list_head;
for (int i = 0; i < pos - 1; i++) // 遍历至pos之前的一个节点
nodePointer = nodePointer->nextNode();
ZTemplate::ZLinkedListNode<T> *delNode = nodePointer->nextNode();// 待删除的节点
nodePointer->setNextNode(nodePointer->nextNode()->nextNode());
delete delNode;
return true;
template<class T>
ZTemplate::Iterator<T> &ZTemplate::ZLinkedList<T>::iterator()
if (nullptr != preIterator)
delete preIterator;
Iterator<T> *_iterator = new ZTemplate::ZLinkedListIterator<T>(*this);
preIterator = _iterator;
return *_iterator;
template<class T>
T & ZTemplate::ZLinkedList<T>::operator[](const rank pos)
ZTemplate::ZLinkedListNode<T> *nodePointer = _list_head;
for (int i = 0; i < pos; i++)
nodePointer = nodePointer->nextNode();
return nodePointer->ref();
template<class T>
bool ZTemplate::ZLinkedList<T>::isEmpty() const
return _length <= 0;
template<class T>
ZTemplate::ZLinkedList<T>::~ZLinkedList<T>()
while (!isEmpty())
remove(0);
链表迭代器的实现
/**链表迭代器类*/
template<class T>
class ZLinkedListIterator : public Iterator<T>
public:
/**
* 构造函数
*/
ZLinkedListIterator<T>(ZLinkedList<T> &list);
/**
* 下一个元素
* @return 返回下一个迭代器
*/
virtual Iterator<T> &next();
/**
* 获取迭代器值
* @return 返回值
*/
virtual const T data() const;
/**
* 是否含有下一个元素
* @return 返回是否有后续元素
*/
virtual bool hasNext() const;
/**
* 重载++
*/
virtual Iterator<T>& operator++();
virtual Iterator<T>& operator++(int);
virtual ~ZLinkedListIterator<T>()_list = nullptr;pointTo = nullptr;
protected:
ZLinkedList<T> *_list; // 迭代器绑定的表
ZLinkedListNode<T> *pointTo; // 当前游标
;
/* 迭代器的实现部分
*/
template<class T>
ZLinkedListIterator<T>::ZLinkedListIterator(ZLinkedList<T> &list)
_list = &list;
pointTo = list._list_head;
template<class T>
Iterator<T>& ZLinkedListIterator<T>::next()
pointTo = pointTo->nextNode();
return *this;
template<class T>
const T ZLinkedListIterator<T>::data() const
return pointTo->data();
template<class T>
bool ZLinkedListIterator<T>::hasNext() const
return nullptr != pointTo;
template<class T>
Iterator<T> & ZLinkedListIterator<T>::operator++()
next();
return *this;
template<class T>
Iterator<T> & ZLinkedListIterator<T>::operator++(int i)
Iterator<T> & tempIt = *(new ZLinkedListIterator<T>(*this));
next();
return tempIt;
以上所涉及的类在前一篇文章中进行查看:C++封装向量-线性表
完整代码为:
//
// ZLinkedList.hpp
// Array
//
// Created by 邹智鹏 on 16/7/3.
// Copyright © 2016年 Frank. All rights reserved.
//
#ifndef ZLinkedList_hpp
#define ZLinkedList_hpp
#include <stdio.h>
#include <list>
#include "Sequence.hpp"
#include "Iterator.hpp"
namespace ZTemplate
/**
* 链表节点类
*/
template<class T>
class ZLinkedListNode
public:
/**
* 默认构造函数,需要目的类型提供默认构造函数å
*/
ZLinkedListNode<T>()_nextNode = nullptr;
/**
* 构造函数,用于构造一个链表节点,并为其制定一个节点值
* @param data 要赋予的节点的值
*/
ZLinkedListNode<T>(const T &data);
/**
* 构建指定前驱的链表节点
* @param data 要指定节点的值
* @param preNode 要指定的上一个节点
*/
ZLinkedListNode<T>(const T &data, ZLinkedListNode &preNode);
/**
* 获取节点值
* @return 返回该节点值的副本,为保证安全,应该相应的数据类型重载赋值和拷贝构造
*/
const T data() constreturn _data;
/**
* 引用该节点的值
* @return 返回节点值的引用
*/
T &ref() return _data;
/**
* 获取下一个节点
* @return 返回下一个节点
*/
ZLinkedListNode<T> *nextNode()return _nextNode;
/**
* 下一个节点的引用
* @return 返回下一个节点指针的引用
*/
ZLinkedListNode<T> *&nextNodeRef()return _nextNode;
/**
* 设置下一个节点
* @param nextNode 要设置的下一个节点
*/
void setNextNode(ZLinkedListNode<T> *nextNode);
protected:
T _data;// 节点数据
ZLinkedListNode<T> *_nextNode; // 下一个节点
;
/*以下为Node的实现*/
template<class T>
ZLinkedListNode<T>::ZLinkedListNode(const T &data)
_data = data;
_nextNode = nullptr;
template<class T>
ZLinkedListNode<T>::ZLinkedListNode(const T &data, ZLinkedListNode &preNode)
_data = data;
// 连接节点
preNode._nextNode = this;
_nextNode = nullptr;
template<class T>
void ZLinkedListNode<T>::setNextNode(ZLinkedListNode<T> *nextNode)
_nextNode = nextNode;
template<class T>
class ZLinkedListIterator;
/**
* 链表类
*/
template<class T>
class ZLinkedList : public Sequence<T>
public:
/**
* 默认构造函数,为节省空间,不设置哨兵节点
*/
ZLinkedList<T>();
/**
* 根据指定值创建链表,该值为链表头部
* @param data 要指定的头部值
*/
ZLinkedList<T>(const T& data);
/**
* 创建指定值的指定个数的链表
* @param data 指定值
* @param count 指定值的个数
*/
ZLinkedList<T>(const T& data, z_size count);
/**
* 插入到最后一个位置
*/
virtual void push_back(const T& val);
/**
* 从指定位置中,移除元素,并返回该元素的副本,若为指针,请自行进行内存管理
* @param pos 元素位置
* @return 返回该元素值
*/
virtual T pop(const rank pos);
/**
* 访问指定位置的值
* @param pos 元素所在的位置
* @return 返回该位置的元素值
*/
virtual const T &at(const rank pos) const;
/**
* 移除指定位置元素
* @param pos 元素所在位置
* @return 返回是否移除成功
*/
virtual bool remove(const rank pos);
/**
* 获取迭代器
* @return 返回迭代器
*/
virtual Iterator<T> &iterator();
/**
* 重载访问器
* @param pos 元素位置
* @return 返回元素引用
*/
virtual T& operator[](const rank pos);
/**
* 判断是否为空表
*/
bool isEmpty() const;
virtual ~ZLinkedList();
z_size length() constreturn _length;
//声明友元关系
friend class ZLinkedListIterator<T>;
protected:
ZLinkedListNode<T> *_list_head; // 链表头结点
ZLinkedListNode<T> *_list_tail; // 链表尾节点,冗余数据,为了加快尾插法的效率
z_size _length; // 长度
Iterator<T> *preIterator; // 上一个迭代器,用于迭代器的释放
;
/**链表迭代器类*/
template<class T>
class ZLinkedListIterator : public Iterator<T>
public:
/**
* 构造函数
*/
ZLinkedListIterator<T>(ZLinkedList<T> &list);
/**
* 下一个元素
* @return 返回下一个迭代器
*/
virtual Iterator<T> &next();
/**
* 获取迭代器值
* @return 返回值
*/
virtual const T data() const;
/**
* 是否含有下一个元素
* @return 返回是否有后续元素
*/
virtual bool hasNext() const;
/**
* 重载++
*/
virtual Iterator<T>& operator++();
virtual Iterator<T>& operator++(int);
virtual ~ZLinkedListIterator<T>()_list = nullptr;pointTo = nullptr;
protected:
ZLinkedList<T> *_list; // 迭代器绑定的表
ZLinkedListNode<T> *pointTo; // 当前游标
;
/* 迭代器的实现部分
*/
template<class T>
ZLinkedListIterator<T>::ZLinkedListIterator(ZLinkedList<T> &list)
_list = &list;
pointTo = list._list_head;
template<class T>
Iterator<T>& ZLinkedListIterator<T>::next()
pointTo = pointTo->nextNode();
return *this;
template<class T>
const T ZLinkedListIterator<T>::data() const
return pointTo->data();
template<class T>
bool ZLinkedListIterator<T>::hasNext() const
return nullptr != pointTo;
template<class T>
Iterator<T> & ZLinkedListIterator<T>::operator++()
next();
return *this;
template<class T>
Iterator<T> & ZLinkedListIterator<T>::operator++(int i)
Iterator<T> & tempIt = *(new ZLinkedListIterator<T>(*this));
next();
return tempIt;
/*
链表的实现
*/
template<class T>
ZTemplate::ZLinkedList<T>::ZLinkedList():Sequence<T>()
_list_head = nullptr;
_length = 0;
_list_tail = nullptr;
preIterator = nullptr;
template<class T>
ZTemplate::ZLinkedList<T>::ZLinkedList(const T &data):Sequence<T>()
_list_head = new ZTemplate::ZLinkedListNode<T>(data);
_length = 1;
preIterator = nullptr;
_list_tail = _list_head;
template<class T>
ZTemplate::ZLinkedList<T>::ZLinkedList(const T &data, ZTemplate::z_size count):Sequence<T>()
_list_head = new ZTemplate::ZLinkedListNode<T>(data);
_length = count;
preIterator = nullptr;
ZTemplate::ZLinkedListNode<T> *curNode = _list_head; // 用于拼接节点
for (int i = 0; i < count - 1; i++)
ZTemplate::ZLinkedListNode<T> *newNode = new ZTemplate::ZLinkedListNode<T>(data, *curNode); // 在构建时,直接追加至末尾
curNode = newNode;
_list_tail = curNode;
template<class T>
void ZTemplate::ZLinkedList<T>::push_back(const T &val)
// 创建节点,直接插入尾部
++_length;
if (_list_head == nullptr) // 头为空
_list_head = _list_tail = new ZLinkedListNode<T>(val);
else
_list_tail = new ZTemplate::ZLinkedListNode<T>(val, *_list_tail);
template<class T>
T ZTemplate::ZLinkedList<T>::pop(const rank pos)
// 节点游标
ZTemplate::ZLinkedListNode<T> *nodePointer = _list_head;
for (int i = 0; i < pos; i++)
nodePointer = nodePointer->nextNode();
return nodePointer->data();
template<class T>
const T& ZTemplate::ZLinkedList<T>::at(const rank pos) const
// 节点游标
ZTemplate::ZLinkedListNode<T> *nodePointer = _list_head;
for (int i = 0; i < pos; i++)
nodePointer = nodePointer->nextNode();
return nodePointer->ref();
template<class T>
bool ZTemplate::ZLinkedList<T>::remove(const rank pos)
if (pos >= _length)
return false;
--_length;
// 头结点删除
if (0 == pos)
ZTemplate::ZLinkedListNode<T> *delNode = _list_head;
_list_head = _list_head->nextNode();
delete delNode;
return true;
// 节点游标
ZTemplate::ZLinkedListNode<T> *nodePointer = _list_head;
for (int i = 0; i < pos - 1; i++) // 遍历至pos之前的一个节点
nodePointer = nodePointer->nextNode();
ZTemplate::ZLinkedListNode<T> *delNode = nodePointer->nextNode();// 待删除的节点
nodePointer->setNextNode(nodePointer->nextNode()->nextNode());
delete delNode;
return true;
template<class T>
ZTemplate::Iterator<T> &ZTemplate::ZLinkedList<T>::iterator()
if (nullptr != preIterator)
delete preIterator;
Iterator<T> *_iterator = new ZTemplate::ZLinkedListIterator<T>(*this);
preIterator = _iterator;
return *_iterator;
template<class T>
T & ZTemplate::ZLinkedList<T>::operator[](const rank pos)
ZTemplate::ZLinkedListNode<T> *nodePointer = _list_head;
for (int i = 0; i < pos; i++)
nodePointer = nodePointer->nextNode();
return nodePointer->ref();
template<class T>
bool ZTemplate::ZLinkedList<T>::isEmpty() const
return _length <= 0;
template<class T>
ZTemplate::ZLinkedList<T>::~ZLinkedList<T>()
while (!isEmpty())
remove(0);
#endif /* ZLinkedList_hpp */
对封装结果进行测试
- 简单类型测试
//
// main.cpp
// Array
//
// Created by 邹智鹏 on 16/7/3.
// Copyright © 2016年 Frank. All rights reserved.
//
#include <iostream>
#include "Array.hpp"
#include "Iterator.hpp"
#include "ZLinkedList.hpp"
using namespace ZTemplate;
int main(int argc, const char * argv[])
ZLinkedList<int> list;
std::cout << "start: " << list.length();
list.push_back(2);
list.push_back(3);
list.push_back(5);
Iterator<int> *iterator = &list.iterator();
std::cout << "--------------------" << std::endl;
while (iterator->hasNext())
std::cout << iterator->data() << std::endl;
(*iterator)++;
list.remove(0);
// 注意对于迭代器而言,只要remove后,迭代器失效,需要重置
std::cout << "--------------------" << std::endl;
iterator = &list.iterator();
while (iterator->hasNext())
std::cout << iterator->data() << std::endl;
(*iterator)++;
std::cout << "--------------------" << std::endl;
return 0;
结果:
- 复杂类型测试
//
// main.cpp
// Array
//
// Created by 邹智鹏 on 16/7/3.
// Copyright © 2016年 Frank. All rights reserved.
//
#include <iostream>
#include "Array.hpp"
#include "Iterator.hpp"
#include "ZLinkedList.hpp"
using namespace ZTemplate;
class Student
public:
Student()name = "", age = 0;
Student(std::string n, int a)name = n, age = a;
Student(const Student &stu)name = stu.name, age = stu.age;
void display() conststd::cout << "name:" << name << ",age:" << age << std::endl;
private:
std::string name;
int age;
;
int main(int argc, const char * argv[])
ZLinkedList<Student> list;
std::cout << "start: " << list.length() << std::endl;
list.push_back(Student("zz", 19));
list.push_back(Student("ee", 20));
list.push_back(Student("ff", 21));
Iterator<Student> *iterator = &list.iterator();
std::cout << "--------------------" << std::endl;
while (iterator->hasNext())
iterator->data().display();
(*iterator)++;
list.remove(0);
// 注意对于迭代器而言,只要remove后,迭代器失效,需要重置
std::cout << "--------------------" << std::endl;
iterator = &list.iterator();
while (iterator->hasNext())
iterator->data().display();
(*iterator)++;
std::cout << "--------------------" << std::endl;
return 0;
测试结果:
由图中显示,基本可以看出测试结果的正确性!
以上是关于C++封装链式表-链表的主要内容,如果未能解决你的问题,请参考以下文章