双向链表,并实现增删查改等功能

首先定义节点类,类成员包含当前节点的值, 指向下一个节点的指针和指向上一个节点的指针

//节点定义
template <typename T>
class Node {
public:
Node<T>* prior;
T value;
Node<T>* next;
Node():value(0),prior(nullptr),next(nullptr) {}
Node(T n):prior(nullptr),value(n),next(nullptr) {}
};

然后是链表类的定义,主要包含了增删查改等功能

//双向链表定义
template <typename T>
class LinkList_doubly {
public:
Node<T>* firstNode;
Node<T>* lastNode; LinkList_doubly();
LinkList_doubly(int n, const T* arr);
LinkList_doubly(const LinkList_doubly<T>& link);
~LinkList_doubly();
LinkList_doubly<T>& push_back(T n);
LinkList_doubly<T>& push_front(T n);
LinkList_doubly<T>& insert(int pos, int n, T* arr);
LinkList_doubly<T>& pop_front();
LinkList_doubly<T>& pop_back();
LinkList_doubly<T>& remove(int pos, int num);
LinkList_doubly<T>& reverse();
T& operator[](int n);
T& at(int n);
LinkList_doubly<T>& replace(int pos, int n, T* arr);
int getLen() {return len;}
void clear() {this->~LinkList_doubly();}
void display();
private:
int len = 0;
Node<T>* getNode_next(int n); };

各个函数解释:

LinkList_doubly();      默认构造函数

LinkList_doubly(const T* arr, int len);      一般构造函数

LinkList_doubly(const LinkList<T>& link)           拷贝构造函数

~LinkList_doubly();     析构函数

LinkList_doubly<T>& push_back(T n);    在尾部添加一个元素

LinkList_doubly<T>& push_front(T n);     在头部添加一个元素

LinkList_doubly<T>& insert(int pos, int n, T* arr);   在pos处插入n个元素

LinkList_doubly<T>& pop_front();    删除第一个节点

LinkList_doubly<T>& pop_back();    删除最后一个节点

LinkList_doubly<T>& remove(int pos, int num);     删除pos开始的num个元素

LinkList_doubly<T>& reverse();     反转链表

T& operator[](int n);     重载[ ]运算符,返回第n个节点的值

T& at(int n);                 与[ ]一样,只不过会检查索引是否越界

LinkList_doubly<T>& replace(int pos, int n, T* arr);    替换n个节点

int getLen() {return len;}     返回长度,因为len是private

void clear() {this->~LinkList();}    清除链表

void display();    显示链表所有元素

Node<T>* getNode_next(int n);     返回第n个节点的next指针

#include <iostream>
using namespace std; template <typename T>
class Node {
public:
Node<T>* prior;
T value;
Node<T>* next;
Node():value(0),prior(nullptr),next(nullptr) {}
Node(T n):prior(nullptr),value(n),next(nullptr) {}
}; template <typename T>
class LinkList_doubly {
public:
Node<T>* firstNode;
Node<T>* lastNode; LinkList_doubly();
LinkList_doubly(int n, const T* arr);
LinkList_doubly(const LinkList_doubly<T>& link);
~LinkList_doubly();
LinkList_doubly<T>& push_back(T n);
LinkList_doubly<T>& push_front(T n);
LinkList_doubly<T>& insert(int pos, int n, T* arr);
LinkList_doubly<T>& pop_front();
LinkList_doubly<T>& pop_back();
LinkList_doubly<T>& remove(int pos, int num);
LinkList_doubly<T>& reverse();
T& operator[](int n);
T& at(int n);
LinkList_doubly<T>& replace(int pos, int n, T* arr);
int getLen() {return len;}
void clear() {this->~LinkList_doubly();}
void display();
private:
int len = 0;
Node<T>* getNode_next(int n); }; //默认构造函数
template <typename T>
LinkList_doubly<T>::LinkList_doubly() {
firstNode = nullptr;
lastNode = nullptr;
len = 0;
} //一般构造函数,用数组进行初始化
template <typename T>
LinkList_doubly<T>::LinkList_doubly(int n, const T* arr) {
Node<T>* temp1 = nullptr;
Node<T>* temp2 = nullptr;
for (int i = 0; i < n; i++) {
temp1 = new Node<T> (arr[i]);
if ( i == 0 )
firstNode = temp1;
if ( i == n-1 )
lastNode = temp1;
temp1->prior = temp2;
if ( i > 0 )
temp2->next = temp1;
temp2 = temp1;
}
this->len = n;
} //拷贝构造函数
template <typename T>
LinkList_doubly<T>::LinkList_doubly(const LinkList_doubly<T>& link) {
this->firstNode = link.firstNode;
this->lastNode = link.lastNode;
this->len = link.getLen();
} //析构函数
template <typename T>
LinkList_doubly<T>::~LinkList_doubly() {
this->len = 0;
Node<T>* temp = firstNode;
lastNode = nullptr;
while ( firstNode ) {
temp = firstNode;
firstNode = firstNode->next;
delete temp;
temp = nullptr;
}
} //在尾部添加一个元素
template <typename T>
LinkList_doubly<T>& LinkList_doubly<T>::push_back(T n) {
Node<T>* newNode = new Node<T> (n);
newNode->prior = lastNode;
lastNode->next = newNode;
lastNode = newNode;
len++;
return *this;
} //在头部添加一个元素
template <typename T>
LinkList_doubly<T>& LinkList_doubly<T>::push_front(T n) {
Node<T>* newNode = new Node<T> (n);
newNode->next = firstNode;
firstNode->prior = newNode;
firstNode = newNode;
len++;
return *this;
} //在position位置插入n个元素
template <typename T>
LinkList_doubly<T>& LinkList_doubly<T>::insert(int pos, int n, T* arr) {
if ( pos < 0 || pos > len-1 ) {
cout << "[error]: illegal insert index, please check" << endl;
exit(0);
}
if ( pos == 0 ) {
for ( int i = 0; i < n; i++ )
this->push_front(arr[n-1-i]); //push_front自带len++
return *this;
}
Node<T>* temp_end = getNode_next(pos);
Node<T>* temp_front = getNode_next(pos-1);
Node<T>* temp_new = nullptr;
for ( int i = 0; i < n; i++ ) {
temp_new = new Node<T> (arr[i]);
temp_front->next = temp_new;
temp_new->prior = temp_front;
temp_front = temp_front->next;
}
temp_front->next = temp_end;
temp_end->prior = temp_front;
len += n;
return *this;
} //删除第一个元素
template <typename T>
LinkList_doubly<T>& LinkList_doubly<T>::pop_front() {
if ( len == 0 ) {
cout << "[warning]: linkedlist is empty" << endl;
return *this;
}
Node<T>* temp = firstNode;
firstNode = firstNode->next;
firstNode->prior = nullptr;
delete temp;
len--;
return *this;
} //删除最后一个元素
template <typename T>
LinkList_doubly<T>& LinkList_doubly<T>::pop_back() {
if ( len == 0 ) {
cout << "[warning]: linkedlist is empty" << endl;
return *this;
}
Node<T>* temp = lastNode;
lastNode = lastNode->prior;
lastNode->next = nullptr;
delete temp;
len--;
return *this;
} //删除position开始的num个元素
template <typename T>
LinkList_doubly<T>& LinkList_doubly<T>::remove(int pos, int num) {
if ( pos > len-1 || len < 0 || pos < 0 || pos > len-1) {
cout << "[error]: illegal remove position, please check again" << endl;
exit(0);
} else if ( pos + num - 1 > len-1) {
cout << "[error]: remove index out of range" << endl;
exit(0);
}
//如果删除了首元节点或者尾节点,要考虑firstNode和lastNode的指向,用pop比较方便
if ( pos == 0 ) {
for ( int i = 0; i < num; i++ )
this->pop_front();
return *this;
}
if ( pos + num == len ) {
for ( int i = 0; i < num; i++ )
this->pop_back();
return *this;
}
Node<T>* temp_front = getNode_next(pos-1);
Node<T>* temp_end = getNode_next(pos+num);
Node<T>* temp = getNode_next(pos);
while ( 1 ) {
Node<T>* node = temp;
temp = temp->next;
delete node;
if ( temp == temp_end ) {
break;
}
}
temp_front->next = temp_end;
temp_end->prior = temp_front;
len -= num;
return *this;
} //替换元素
template <typename T>
LinkList_doubly<T>& LinkList_doubly<T>::replace(int pos, int n, T* arr) {
Node<T>* temp = getNode_next(pos);
for ( int i = 0; i < n; i++ ) {
temp->value = arr[i];
temp = temp->next;
}
return *this;
} //反转链表,终极偷懒写法,实在不想动脑子了
template <typename T>
LinkList_doubly<T>& LinkList_doubly<T>::reverse() {
const int num = len;
T arr[num];
Node<T>* temp = firstNode;
for ( int i = 0; i < this->len; i++ ) {
arr[i] = temp->value;
temp = temp->next;
}
temp = lastNode;
for ( int i = 0; i < this->len; i++ ) {
temp->value = arr[i];
temp = temp->prior;
}
return *this;
} //访问第n个元素
template <typename T>
T& LinkList_doubly<T>::operator[](int n){
Node<T>* temp = nullptr;
if ( n <= len/2 ) {
temp = firstNode;
for ( int i = 0; i < n; i++ ) {
temp = temp->next;
}
} else {
temp = lastNode;
for ( int i = 0; i < len-1-n; i++ ) {
temp = temp->prior;
}
}
return temp->value; } //访问第n个元素,增加索引检查 template <typename T>
T& LinkList_doubly<T>::at(int n){
if ( n < 0 || n > len-1 ) {
cout << "[error]:index out of range" << endl;
exit(0);
}
return (*this)[n];
}
//获取第n个Node的next指针
template <typename T>
Node<T>* LinkList_doubly<T>::getNode_next(int n) {
if ( n > len-1 ) {
cout << "[error]: illegal index" << endl;
}
Node<T>* temp = firstNode;
for ( int i = 0; i < n; i++ ) {
temp = temp->next;
}
return temp;
} //显示链表所有元素,会对链表正反向一致性进行检查
template <typename T>
void LinkList_doubly<T>::display() {
const int num = len;
T arr1[num];
T arr2[num];
Node<T>* temp = firstNode;
for ( int i = 0; i < this->len; i++ ) {
arr1[i] = temp->value;
temp = temp->next;
}
temp = lastNode;
for ( int i = 0; i < this->len; i++ ) {
arr2[i] = temp->value;
temp = temp->prior;
}
for ( int i = 0; i < this->len; i++ ) {
if ( arr1[i] != arr2[len-1-i] ) {
cout << "第"<<i<<"个元素正反向结果不一致" << arr1[i] << " " << arr2[len-1-i] << endl;
exit(0);
}
} temp = firstNode;
for ( int i = 0; i < this->len; i++ ) {
cout << temp->value << " ";
temp = temp->next;
}
cout << endl;
} int main() {
int arr[] = {1,5,7,3,5,3,1};
LinkList_doubly<int> link(sizeof(arr)/sizeof(int), arr);
link.display();
link.push_back(25);
link.display();
link.push_front(10);
link.display();
int arr2[] = {1,0,0,4};
link.insert(0,sizeof(arr2)/sizeof(int), arr2);
link.display();
link.pop_front();
link.display();
link.pop_back();
link.display();
link.remove(7,2);
link.display();
int arr3[] = {2,3,5};
link.replace(4, sizeof(arr3)/sizeof(int), arr3);
link.display();
link.reverse();
link.display();
cout << link[8] << " " << link.at(3) << endl;
cout << link.getLen() << endl;
link.~LinkList_doubly();
cout << link.getLen() << endl; }

C++ 手动实现双向链表(作业版)的更多相关文章

  1. 手动实现一个简易版SpringMvc

    版权声明:本篇博客大部分代码引用于公众号:java团长,我只是在作者基础上稍微修改一些内容,内容仅供学习与参考 前言:目前mvc框架经过大浪淘沙,由最初的struts1到struts2,到目前的主流框 ...

  2. 《剑指offer》面试题27 二叉搜索树与双向链表 Java版

    (将BST改成排序的双向链表.) 我的方法一:根据BST的性质,如果我们中序遍历BST,将会得到一个从小到大排序的序列.如果我们将包含这些数字的节点连接起来,就形成了一个链表,形成双向链表也很简单.关 ...

  3. 【react】---手动封装一个简易版的redux

    export let createStore = (reducer)=>{ //定义默认的state let state; //定义默认的action let actionTypes = &qu ...

  4. 【react】---手动封装一个简易版的redux---【巷子】

    export let createStore = (reducer)=>{ //定义默认的state let state = {}; //定义默认的action let actionTypes ...

  5. mysql5.7.23手动配置安装windows版

    1.mysql下载地址 官网:https://dev.mysql.com/downloads/mysql/5.7.html#downloads 官网我下载的是: 百度网盘:链接: https://pa ...

  6. 小米2S 小米手机如何手动升级到开发版

    1 从官网下载系统的更新包,比如对于小米2S,从下面的网址下载. http://www.miui.com/download-2.html     2 下载完成之后,放到手机的任意文件夹下,比如下面的S ...

  7. SQL Server代理(10/12):使用代理账号运行作业

    SQL Server代理是所有实时数据库的核心.代理有很多不明显的用法,因此系统的知识,对于开发人员还是DBA都是有用的.这系列文章会通俗介绍它的很多用法. 在这一系列的上一篇,你查看了msdb库下用 ...

  8. 多个Linux发行版安装ss服务端

    本文仅做技术探讨,请在遵守相应的法律法规的前提下使用. Centos 7一键安装脚本 简单快捷,随机生成密码,默认端口默认加密类型 bash <(curl -s http://morning.w ...

  9. Linux_控制作业(管理)

    一.作业控制 1.作业控制与回话 1️⃣:作业控制是shell的一种功能,它允许单个shell实例运行和管理多个命令 2️⃣:作业与在sehll提示符中输入的每个管道相关联.该管道中的所有进程均是作业 ...

  10. CentOS7安装配置Bacula yum方法

    参考: https://www.baidu.com/link?url=o2QIy2YZWjsJPAFJuYFhrH3nPvtyRkSe-o5Q_FqFZ5E1EMOsIOmGeKm0HAonwHOw8 ...

随机推荐

  1. Windows2016安装.NetFramework 3.5

    Windows2016安装.NetFramework 3.5 Windows2016服务器默认安装的是 .Net 4.6.2版本,但是有时候我们经常会需要用到.Net 3.5版本.以下介绍的是在线和离 ...

  2. Kubernetes--管理Pod对象的容器(3)

    共享节点的网络名称空间 同一个Pod对象的各容器均运行于一个独立的.隔离的Network名称空间中,共享同一个网络协议栈及相关的网络设备.也有一些特殊的Pod对象需要运行于所在节点的名称空间中,执行系 ...

  3. What does int main(int argc, char *argv[]) mean?

    忽然发现自己不理解许多代码中这行的含义是什么...(汗颜) 下面贴一段stackoverflow上面的回答: argv and argc are how command line arguments ...

  4. shell语法5-判断语句、循环语句、函数

    一.判断语句 if-then形式类似于C/C++中的if-else语句. 1.单层if命令格式:if conditionthen    语句1    语句2    ...fi 2.单层if-else命 ...

  5. TP开发项目时遇到的问题记录

    1.下载功能. TP自带Http下载类,使用时new一个就行,示例代码: public function download(){ //接收公文id $id = I('get.fid'); //根据公文 ...

  6. 【博客】如何在Github上创建博客

    [博客]如何在Github上创建博客 1. 安装nodejs windows安装npm教程--nodejs 2. 安装hexo npm install -g hexo-cli 3. 搭建博客 $ he ...

  7. 树莓派zero W ,连接墨水屏(2.13inch_e-Paper_HAT (V3))

    墨水瓶型号:    2.13inch_e-Paper_HAT (V3) https://www.waveshare.net/wiki/2.13inch_e-Paper_HAT 与树莓派 Zero 连接 ...

  8. 分布式锁 -- redis

    原理 redis设置一个key和value,如果存在则获取锁失败,不存在则获取锁成功处理业务,业务处理完成后删除这条数据,可以带个失效时间. 代码 public void handleInvoice( ...

  9. 第一次写,python爬虫图片,操作excel。

    第一次写博客,其实老早就注册博客园了,有写博客的想法,就是没有行动,总是学了忘,忘了丢,最后啥都没有,电脑里零零散散,东找找,西看看,今天认识到写博客的重要性. 最近闲着看了潭州教育的在线直播课程,颇 ...

  10. element3 form表单校验对象里面有对象的情况

    let formSearch = reactive({ queryParam: [ { field: "", //查询的字段 gzcs: "", //规则参数 ...