单向循环链表,并实现增删查改等功能

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

循环链表的尾节点指向头节点

节点定义:

//node definition
template <typename T>
class Node {
public:
T value;
Node<T>* next; Node() {}
Node(const T& value) {
this->value = value;
next = nullptr;
}
Node(const T& value, const Node<T>& next) {
this->value = value;
this->next = next;
}
};

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

//LinkList_cycle definition
template <typename T>
class LinkList_cycle {
public:
Node<T>* headnode; LinkList_cycle();
LinkList_cycle(const T* arr, int len); //array initial
LinkList_cycle(const LinkList_cycle<T>& link);
~LinkList_cycle();
LinkList_cycle<T>& push_back(T n);
LinkList_cycle<T>& push_front(T n);
LinkList_cycle<T>& insert(int pos, int n, T* arr);
LinkList_cycle<T>& pop_front();
LinkList_cycle<T>& pop_back();
LinkList_cycle<T>& remove(int pos, int num);
LinkList_cycle<T>& reverse();
T& operator[](int n);
T& at(int n);
LinkList_cycle<T>& replace(int pos, int n, T* arr);
int getLen() {return len;}
void clear() {this->~LinkList_cycle();}
void display();
private:
int len = 0;
Node<T>* getNode(int n); };

各个函数解释:

LinkList_cycle();      默认构造函数

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

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

~LinkList_cycle();     析构函数

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

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

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

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

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

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

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

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

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

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

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

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

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

Node<T>* getNode(int n);     返回第n个节点的指针,是private函数,在其他函数中经常用到

完整代码:

#include <iostream>
using namespace std; //node definition
template <typename T>
class Node {
public:
T value;
Node<T>* next; Node() {}
Node(const T& value) {
this->value = value;
next = nullptr;
}
Node(const T& value, const Node<T>& next) {
this->value = value;
this->next = next;
}
}; //LinkList_cycle definition
template <typename T>
class LinkList_cycle {
public:
Node<T>* headnode; LinkList_cycle();
LinkList_cycle(const T* arr, int len); //array initial
LinkList_cycle(const LinkList_cycle<T>& link);
~LinkList_cycle();
LinkList_cycle<T>& push_back(T n);
LinkList_cycle<T>& push_front(T n);
LinkList_cycle<T>& insert(int pos, int n, T* arr);
LinkList_cycle<T>& pop_front();
LinkList_cycle<T>& pop_back();
LinkList_cycle<T>& remove(int pos, int num);
LinkList_cycle<T>& reverse();
T& operator[](int n);
T& at(int n);
LinkList_cycle<T>& replace(int pos, int n, T* arr);
int getLen() {return len;}
void clear() {this->~LinkList_cycle();}
void display();
private:
int len = 0;
Node<T>* getNode(int n); }; //default constructor
template <typename T>
LinkList_cycle<T>::LinkList_cycle() {
headnode = nullptr;
len = 0;
} //normal constructor
template <typename T>
LinkList_cycle<T>::LinkList_cycle(const T* arr, int len) {
Node<T>* temp = nullptr;
Node<T>* node = nullptr;
if ( len < 0 ) {
cout << "[error]: illegal length of LinkList_cycle" << endl;
exit(0);
}
node = new Node<T>(arr[0]);
headnode = node;
temp = node;
for ( int i = 1; i < len; i++ ) {
node = nullptr;
node = new Node<T> (arr[i]);
temp->next = node;
temp = temp->next;
}
temp->next = headnode;;
this->len = len;
} //copy constructor
template <typename T>
LinkList_cycle<T>::LinkList_cycle(const LinkList_cycle<T>& link) {
this->len = link.getLen();
this->headnode = link.headnode;
} //deconstructor
template <typename T>
LinkList_cycle<T>::~LinkList_cycle() {
if ( headnode == nullptr || len == 0 ) {
headnode = nullptr;
len = 0;
return;
}
this->len = 0;
Node<T>* temp1 = headnode;
Node<T>* temp2 = headnode; //保存headnode
while ( headnode != nullptr ) {
temp1 = headnode;
headnode = headnode->next;
delete temp1;
if ( headnode == temp2 ) //如果next指向headnode了,说明当前的temp1就是最后一个节点了
break;
temp1 = nullptr;
}
headnode = nullptr;
} //display all elements in LinkList_cycle<T>
template <typename T>
void LinkList_cycle<T>::display() {
if ( this->len == 0 ) {
cout << "[warning]: can not display empty linkedlist" << endl;
return;
}
Node<T> *node = headnode;
for ( int i = 0; i < len; i++ ) {
cout << node->value << " ";
node = node->next;
}
if ( node != headnode ) {
cout << "[error]: the last node->next do not point to headnode, check again" << endl;
}
node = nullptr;
cout << endl;
} //add one node at the last position
template <typename T>
LinkList_cycle<T>& LinkList_cycle<T>::push_back(T n) {
Node<T> *node = this->getNode(len-1); //获取指向第len-1个node的指针,即len-2节点的next,所以node就是指向最后节点的指针 if ( node->next == headnode ) { //再加一层保护
Node<T> *temp = new Node<T>(n); //创建新node
node->next = temp; //将最后一个节点的next指向新node
temp->next = headnode; //将新node->next指向headnode
this->len++;
}
return *this;
} //add one node at the first position
template <typename T>
LinkList_cycle<T>& LinkList_cycle<T>::push_front(T n) {
Node<T>* node_new = new Node<T>(n); //新节点
Node<T> *node_end = this->getNode(len-1); //最后节点
node_new->next = headnode; //新节点的next指向第一个节点
node_end->next = node_new; //最后节点的next指向新节点
headnode = node_new; //再让headnode指向新节点
this->len++;
return *this;
} //insert elements to LinkList_cycle
template <typename T>
LinkList_cycle<T>& LinkList_cycle<T>::insert(int pos, int n, T* arr) {
if ( pos > len-1 || len < 0 ) {
cout << "[error]: illegal insert position, please check again" << endl;
exit(0);
}
Node<T>* node_N = getNode(len-1); //前半部分
Node<T>* temp = node_N->next; //后半部分
Node<T>* node_new = nullptr; //新增加的
for ( int i = 0; i < n; i++ ) {
node_new = new Node<T> (arr[n-1-i]);
node_new->next = temp;
temp = node_new;
node_new = nullptr;
}
node_N->next = temp;
if ( pos == 0) //唯有再0处插入的时候,需要改变头节点,其实对pos=0,一直push_front也行
headnode = temp;
this->len += n;
return *this;
} //delete the first element
template <typename T>
LinkList_cycle<T>& LinkList_cycle<T>::pop_front() {
if ( this->len == 0 ) {
cout << "[error]: LinkList_cycle don't has any element" << endl;
exit(0);
}
Node<T>* temp = headnode; //先复制一份headnode
headnode = headnode->next; //headnode 前进一步
delete temp; //把第一个节点释放掉
this->len--;
temp = getNode(len-1); //获取最后一个节点
temp->next = headnode; //把最后一个节点的next指向新的headnode
return *this;
} //delete the last element
template <typename T>
LinkList_cycle<T>& LinkList_cycle<T>::pop_back() {
if ( this->len == 0 ) {
cout << "[error]: LinkList_cycle don't has any element" << endl;
exit(0);
}
Node<T>* temp1 = getNode(len-2);
Node<T>* temp2 = temp1->next;
delete temp2;
temp1->next = headnode;
this->len--;
return *this;
} //get the last node pointer
template <typename T>
Node<T>* LinkList_cycle<T>::getNode(int n) {
if ( n > len-1 || n < 0) {
cout << "[warning]: index out of range" <<endl;
}
n = n%len;
if ( n < 0 )
n = n + len;
Node<T> *node = headnode;
for( int i = 0; i < n; i++ ) {
node = node->next;
}
return node;
} //remove n elements
template <typename T>
LinkList_cycle<T>& LinkList_cycle<T>::remove(int pos, int num) {
if ( pos > len-1 || len < 0 ) {
cout << "[error]: illegal remove position, please check again" << endl;
exit(0);
} else if ( pos + num > len) {
cout << "[error]: remove index out of range" << endl;
exit(0);
}
Node<T>* node_N = getNode(pos-1);
Node<T>* node_N_num = getNode(pos+num);
Node<T>* temp = getNode(pos);
while ( 1 ) {
Node<T>* node = temp;
temp = temp->next;
if ( temp == node_N_num ) {
break;
}
delete node;
}
if ( pos == 0 ) { //如果从0位置开始删除,要修改头节点
headnode = node_N_num;
node_N->next = headnode;
}
node_N->next = node_N_num;
this->len -= num;
return *this;
} //reverse LinkList_cycle
template <typename T>
LinkList_cycle<T>& LinkList_cycle<T>::reverse() {
const int num = len;
T arr[num];
Node<T>* temp = headnode;
for ( int i = 0; i < this->len; i++ ) {
arr[i] = temp->value;
temp = temp->next;
}
temp = headnode;
for ( int i = 0; i < this->len; i++ ) {
temp->value = arr[len-i-1];
temp = temp->next;
}
return *this;
} template <typename T>
T& LinkList_cycle<T>::operator[](int n) {
return this->getNode(n)->value;
} template <typename T>
LinkList_cycle<T>& LinkList_cycle<T>::replace(int pos, int n, T* arr) {
if ( pos > len-1 || len < 0 ) {
cout << "[error]: illegal remove position, please check again" << endl;
exit(0);
} else if ( pos + n > len) {
cout << "[error]: remove index out of range" << endl;
exit(0);
}
Node<T>* temp = nullptr;
if ( pos == 0 )
temp = headnode;
else
temp = this->getNode(pos);
for ( int i = 0; i < n; i++ ) {
temp->value = arr[i];
temp = temp->next;
}
return *this;
} int main(){
int arr[]{1,2,4,5,0};
LinkList_cycle<int> link(arr, sizeof(arr)/sizeof(int));
cout << "LinkLint init with arr: " <<endl;
link.display();
cout << "push_back:" << endl;
link.push_back(34);
link.display();
cout << "push_front:" << endl;
link.push_front(10);
link.display();
cout << "insert:" << endl;
link.insert(0,4,arr);
link.display();
cout << "pop_front:" << endl;
link.pop_front();
link.display();
cout << "pop_back:" << endl;
link.pop_back();
link.display();
cout << "remove:" << endl;
link.remove(0,3);
link.display();
cout << "[] operator:" << endl;
cout << link[2] << endl;
cout << "replace:" << endl;
int a[] = {6,5,2};
link.replace(0, sizeof(a)/sizeof(int), a);
link.display();
cout << "LinkList_cycle reserve:" << endl;
link.reverse();
link.display();
cout << "clear:" << endl;
link.clear();
cout << "len=" << link.getLen() << endl;
link.display();
}

C++ 手动实现单向循环链表(课后作业版)的更多相关文章

  1. String字符串类课后作业

    String动手动脑和课后作业 请运行以下示例代码StringPool.java,查看其输出结果.如何解释这样的输出结果?从中你能总结出什么? 结果: 总结:在Java中,内容相同的字串常量(&quo ...

  2. JAVA第三周课后作业

    JAVA课后作业 一.枚举类型 代码: enum Size{SMALL,MEDIUM,LARGE}; public cl ass EnumTest { public static void main( ...

  3. java课后作业

    课后作业之字串加密: 设计思想: 1.输入要加密的英文子串str 2.定义num=str的字符串长度 3.将字符串转化为单个字符 4.每个字符+3,向后移3个 5.定义str1,将新得到的每个字符加到 ...

  4. 基于visual Studio2013解决算法导论之021单向循环链表

     题目 单向循环链表的操作 解决代码及点评 #include <stdio.h> #include <stdlib.h> #include <time.h> ...

  5. Python 单向循环链表

    操作 is_empty() 判断链表是否为空 length() 返回链表的长度 travel() 遍历 add(item) 在头部添加一个节点 append(item) 在尾部添加一个节点 inser ...

  6. 单向循环链表C语言实现

    我们都知道,单向链表最后指向为NULL,也就是为空,那单向循环链表就是不指向为NULL了,指向头节点,所以下面这个程序运行结果就是,你将会看到遍历链表的时候就是一个死循环,因为它不指向为NULL,也是 ...

  7. python中的单向循环链表实现

    引子 所谓单向循环链表,不过是在单向链表的基础上,如响尾蛇般将其首尾相连,也因此有诸多类似之处与务必留心之点.尤其是可能涉及到头尾节点的操作,不可疏忽. 对于诸多操所必须的遍历,这时的条件是什么?又应 ...

  8. python基础一之课后作业:编写登录接口

    1 # Author : Mamba 2 3 #python基础一之课后作业:编写登录接口 4 5 # 输入用户名密码 6 # 认证成功后显示欢迎信息 7 # 用户名3次输入错误后,退出程序 8 # ...

  9. c/c++ 线性表之单向循环链表

    c/c++ 线性表之单向循环链表 线性表之单向循环链表 不是存放在连续的内存空间,链表中的每个节点的next都指向下一个节点,最后一个节点的下一个节点不是NULL,而是头节点.因为头尾相连,所以叫单向 ...

  10. 吴恩达课后作业学习1-week4-homework-two-hidden-layer -1

    参考:https://blog.csdn.net/u013733326/article/details/79767169 希望大家直接到上面的网址去查看代码,下面是本人的笔记 两层神经网络,和吴恩达课 ...

随机推荐

  1. 用python从网页下载单词库

    从网站下载单词库 1 每一页有几百个单词 2 每一个单词有独立的URL,URL中包含单词的中文解释 3 使用的库 requests,pyquery,web #coding:utf-8 import r ...

  2. Codeforces Global Round 17

    Codeforces Global Round 17 A. Anti Light's Cell Guessing 坑点:\(n=1,m=1\) 时答案为 \(0\) . 其他情况:当 \(n=1\) ...

  3. uni-app配置钉钉小程序步骤

    1.创建项目 2.在项目根目录配置或者新建package.json文件,配置代码 { "uni-app": { "scripts": { "mp-di ...

  4. IE和FireFox 对FORM enctype属性的认识存在差异

    IE和FireFox 对FORM enctype属性的认识存在差异,一般来说对于动态创建的form,如果因为要上传文件的原因很自然的会使用类似如下的代码: 1  //create form 2  th ...

  5. beanshell 响应数据的解析与变量的保存

    获取响应的数据 response = prev.getResponseDataAsString() //prev.getResponseDataAsString是Jmeter提供的方法,可以调取上次请 ...

  6. 2023-03-03 js map 双重嵌套

    恩..其实也没啥要记录的,记住关键一点就是必须要有return,不管是几重,比如: arr.map((item, index) => {     return (         item.ar ...

  7. PR如何导出mp4格式的视频

    PR如何导出mp4格式的视频 PR是一款强大的视频处理软件,有时我们想导出mp4格式的视频,但好像找不到这种格式,具体怎么操作呢?PR如何导出mp4格式的视频? 1.打开PR,然后处理完视频后,点击左 ...

  8. nohup文件的压缩分割

    编写sh脚本 先拷贝,之后,清空. 待完成,压缩功能 #!/bin/sh #description split logs time1=$(date -d 'yesterday' "+%Y%m ...

  9. mysql索引 数据库优化

    1.mysql索引结构b+树 a.首先要说二叉树,二叉查找树,数的结构不用多说,二叉查找树,大概就是几个原则,左边比右边的小,然后保持一个分布均匀,也就是树的高度尽量最小. b.b-树,b-树和二叉查 ...

  10. 头条二面:宕机后,Redis如何实现快速恢复?

    Redis作为非常火热的内存数据库,其除了具有非常高的性能之外,还需要保证高可用,在故障发生时,尽可能地降低故障带来的影响,Redis也提供了完善的故障恢复机制:哨兵.下面就来具体来看看Redis的故 ...