C++ 手动实现单向循环链表(课后作业版)
单向循环链表,并实现增删查改等功能
首先定义节点类,类成员包含当前节点的值, 指向下一个节点的指针
循环链表的尾节点指向头节点
节点定义:
//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++ 手动实现单向循环链表(课后作业版)的更多相关文章
- String字符串类课后作业
String动手动脑和课后作业 请运行以下示例代码StringPool.java,查看其输出结果.如何解释这样的输出结果?从中你能总结出什么? 结果: 总结:在Java中,内容相同的字串常量(&quo ...
- JAVA第三周课后作业
JAVA课后作业 一.枚举类型 代码: enum Size{SMALL,MEDIUM,LARGE}; public cl ass EnumTest { public static void main( ...
- java课后作业
课后作业之字串加密: 设计思想: 1.输入要加密的英文子串str 2.定义num=str的字符串长度 3.将字符串转化为单个字符 4.每个字符+3,向后移3个 5.定义str1,将新得到的每个字符加到 ...
- 基于visual Studio2013解决算法导论之021单向循环链表
题目 单向循环链表的操作 解决代码及点评 #include <stdio.h> #include <stdlib.h> #include <time.h> ...
- Python 单向循环链表
操作 is_empty() 判断链表是否为空 length() 返回链表的长度 travel() 遍历 add(item) 在头部添加一个节点 append(item) 在尾部添加一个节点 inser ...
- 单向循环链表C语言实现
我们都知道,单向链表最后指向为NULL,也就是为空,那单向循环链表就是不指向为NULL了,指向头节点,所以下面这个程序运行结果就是,你将会看到遍历链表的时候就是一个死循环,因为它不指向为NULL,也是 ...
- python中的单向循环链表实现
引子 所谓单向循环链表,不过是在单向链表的基础上,如响尾蛇般将其首尾相连,也因此有诸多类似之处与务必留心之点.尤其是可能涉及到头尾节点的操作,不可疏忽. 对于诸多操所必须的遍历,这时的条件是什么?又应 ...
- python基础一之课后作业:编写登录接口
1 # Author : Mamba 2 3 #python基础一之课后作业:编写登录接口 4 5 # 输入用户名密码 6 # 认证成功后显示欢迎信息 7 # 用户名3次输入错误后,退出程序 8 # ...
- c/c++ 线性表之单向循环链表
c/c++ 线性表之单向循环链表 线性表之单向循环链表 不是存放在连续的内存空间,链表中的每个节点的next都指向下一个节点,最后一个节点的下一个节点不是NULL,而是头节点.因为头尾相连,所以叫单向 ...
- 吴恩达课后作业学习1-week4-homework-two-hidden-layer -1
参考:https://blog.csdn.net/u013733326/article/details/79767169 希望大家直接到上面的网址去查看代码,下面是本人的笔记 两层神经网络,和吴恩达课 ...
随机推荐
- docker下载java镜像,执行xxx.jar文件
docker pull java:8u111
- 注意注意!!!!关于keil的问题,调试时候的bug
1.keil变量不区分大小写: 2.KEIL调试debug时误报,未定义某变量 但是实际定义了的. 今天用keil写代码 感觉逻辑上没问题 但是始终不是那个效果 检查了半天错误问题.最后debug居然 ...
- Fiddler抓包原理与操作
https://www.cnblogs.com/TankXiao/archive/2012/02/06/2337728.html#2306864
- 网络协议及osi模型
osi模型:由高到底 应用层:最高一层,是用户与网络的接口 表示层: 会话层: 传输层:作用是为上层协议提供端到端的可靠和透明的数据传输服务 网络层: 数据链路层: 物理层:它利用传输介质为数据链路层 ...
- 对词向量模型Word2Vec和GloVe的理解
Word2Vec Word2Vec 是 google 在2013年提出的词向量模型,通过 Word2Vec 可以用数值向量表示单词,且在向量空间中可以很好地衡量两个单词的相似性. 简述 我们知道,在使 ...
- class_task
#!/usr/bin/python # -*- coding: UTF-8 -*- class Task(): _cls_name = "cls name" def ...
- QueryDet: Cascaded Sparse Query for Accelerating High-Resolution Small Object Detection(QueryDet:用于加速高分辨率小目标检测的级联稀疏查询)
QueryDet: Cascaded Sparse Query for Accelerating High-Resolution Small Object Detection(QueryDet:用于加 ...
- 力扣53. 最大子数组和(dp)
给你一个整数数组 nums ,请你找出一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和. 子数组 是数组中的一个连续部分. 示例 1: 输入:nums = [-2,1,-3,4,-1 ...
- JS基础笔记汇总
JS基础笔记最全的汇总 javascript介绍以及起源目录1.变量和常量的知识2.基本数据类型3.运算符4.基本数据类型间的转换5.流程控制语句 一.javascript介绍以及起源 js一种直译型 ...
- centons7.2 双网口聚合功能配置和验证
1.启动网络管理器运行systemctl restart NetworkManager2.创建主备绑定连接 nmcli connection add con-name bond0 type bond ...