[朝花夕拾]单链表篇-C++
本例结合模板对单链表进行了一个简单的C++实现,可为数据结构新手进行学习提供参考,中间可能有考虑不周之处烦请指出,该文章属于作者原创文章,当前时间节点前全网没有第二篇,转载请注明出处,支持个人劳动成果。
单链表结构定义-
头文件 singly_list.h
#ifndef SIGNLY_LIST
#define SIGNLY_LIST
#include<iostream>
using namespace std;
template<typename T>
class Node {
public:
Node(const T& _data, Node* _next = NULL)
{
data = _data; // 数据结构T若不对=进行重载就会发生浅拷贝现象,导致内存错误
next = _next;
}
public:
T data;
Node* next;
};
template<typename T>
class SinglyList {
private:
Node<T>* header; // 头节点指针
int m_size; // 链表长度
private:
bool isInvalidPos(int pos);
public:
SinglyList();
~SinglyList();
bool isEmpty()const;
int size();
void add(const Node<T>& _node,int pos);
void addToTail(const Node<T>& _node);
void remove(int pos);
void update(const Node<T>& _node,int pos);
Node<T> getNode(int pos);
void printList();
};
#endif
template<typename T>
inline bool SinglyList<T>::isInvalidPos(int pos)
{
return (pos<0 || pos>=m_size)?true:false;
}
// 初始化单链表
template<typename T>
inline SinglyList<T>::SinglyList()
{
header = NULL;
m_size = 0;
}
// 析构函数,释放单链表空间
template<typename T>
inline SinglyList<T>::~SinglyList()
{
if (m_size > 0) {
// destroy memory
Node<T>* ptr = header;
while (header->next != NULL) {
header = header->next;
ptr->next = NULL;
delete ptr;
ptr = header;
}
}
}
// 判断单链表是否为空或长度是否为零
template<typename T>
inline bool SinglyList<T>::isEmpty() const
{
return m_size==0 || header==NULL;
}
// 返回单链表长度
template<typename T>
inline int SinglyList<T>::size()
{
return m_size;
}
// 在单链表某个位置增加一个节点
template<typename T>
inline void SinglyList<T>::add(const Node<T>& _node, int pos)
{
if (isInvalidPos(pos)) {
cout << "pos invalid!\n";
return;
}
else {
Node<T>* prev = header;
Node<T>* ptr=header;
for (int i = 0; i < pos; i++) {
ptr=ptr->next;
if (i == pos - 1)
continue;
prev=prev->next;// 保证在pos的前一个节点
}
// 当前ptr指针指向位置为pos处的节点
// 设置新节点的next指向该pos处的节点的起始位置
Node<T>* node = new Node<T>(_node.data,ptr);
prev->next = node;// prev指针指向刚才新添加入的节点的起始地址
m_size++;
}
}
// 在单链表的末尾增加一个节点
template<typename T>
inline void SinglyList<T>::addToTail(const Node<T>& _node)
{
if (m_size == 0) {
header = new Node<T>(_node.data, NULL);
m_size++;
}
else if(m_size>0){
Node<T>* prev = header;
Node<T>* ptr = header;
while (ptr) {
ptr=ptr->next;
if (ptr == NULL) {
cout << "end while.\n";
break;
}
prev = ptr;
}
if (prev != NULL) {
prev->next = new Node<T>(_node.data, NULL);
}
m_size++;
}
}
// 移除单链表中某个位置的节点
template<typename T>
inline void SinglyList<T>::remove(int pos)
{
if (isInvalidPos(pos)) {
cout << " invalid pos! \n";
return;
}
else {
if (pos > 0) {
Node<T>* prev = header;
Node<T>* ptr = header;
for (int i = 0; i < pos; i++) {
ptr = ptr->next;
if (i == pos - 1)
continue;
prev = prev->next;
}
prev->next = ptr->next;
ptr->next = NULL;
delete ptr; // 释放掉这块内存,不知道是否存在问题,如果这块内存不是从堆区申请的,那咋办嘞
ptr = NULL;
}
else if(pos==0){
Node<T>* ptr = header;
header = header->next;
ptr->next = NULL;
delete ptr;
ptr = NULL;
}
}
}
// 对单链表中某个位置的节点进行更新
template<typename T>
inline void SinglyList<T>::update(const Node<T>& node, int pos)
{
if (isInvalidPos(pos)) {
cout << "invalid pos!\n";
return;
}
else {
Node<T>* ptr = header;
for (int i = 0; i < pos; i++) {
ptr=ptr->next;
}
ptr->data = node.data;
}
}
// 得到单链表中某个位置的节点数据
template<typename T>
inline Node<T> SinglyList<T>::getNode(int pos)
{
if (isInvalidPos(pos)) {
cout << "invalid pos!\n";
return Node<T>(T());
}
else {
Node<T>* ptr = header;
for (int i = 0; i < pos; i++) {
ptr=ptr->next;
}
Node<T> node = Node<T>(ptr->data, ptr->next);
return node;
}
}
template<typename T>
inline void SinglyList<T>::printList()
{
if (m_size <= 0) {
cout << "There is no data in list...\n";
return;
}
else {
Node<T>* ptr = header;
do {
// 要求T数据进行<<流操作符的重载,所以说这个函数定义在SinglyList应该是不妥当的,暂且先这样处理
cout << ptr->data;
ptr = ptr->next;
} while (ptr!=NULL);
}
}
测试数据结构定义
头文件 student.h
#pragma once
#include<string>
#include<iostream>
using namespace std;
class Student {
public:
Student();
Student(long id, string name);
~Student();
friend ostream& operator<<(ostream& os,const Student& _student);
private:
long m_id=-1L;
string m_name="invalid name";
};
源文件 student.cpp
#include "student.h"
Student::Student()
{
}
Student::Student(long id, string name)
{
m_id = id;
m_name = name;
}
Student::~Student()
{
}
ostream& operator<<(ostream& os, const Student& _student)
{
// TODO: 在此处插入 return 语句
return (os<<"[ " << _student.m_id << ", "<<_student.m_name<<" ]\n");
}
简单的测试函数编写-main函数
#include "singly_list.h"
#include "student.h"
#include<iostream>
using namespace std;
int main() {
SinglyList<Student> list;
// 测试addToTail函数
list.addToTail(Student(1L, "鸣人"));
list.addToTail(Student(2L,"佐助"));
list.addToTail(Student(3L, "旗木卡卡西"));
// 测试size函数
cout << "当前单链表的长度为: " << list.size() << "\n";
// 输出当前链表信息
list.printList();
cout << "\n";
// 测试add函数
list.add(Student(4L, "斑"),2);
// 输出当前链表信息
cout << "当前单链表的长度为: " << list.size() << "\n";
list.printList();
// 待测函数
cout << "测试 isEmpty函数...\n";
cout << (list.isEmpty() ? "是" : "否") << "\n";
cout << "测试remove函数...\n";
list.remove(0);
list.printList();
list.addToTail(Student(7L, "红凯"));
list.printList();
// 测试update函数
cout << "测试update函数...\n";
Node<Student> node(Student(101L,"我爱罗"));
list.update(node, 3);
list.printList();
// 越界测试
cout << "测试update函数(越界测试)...\n";
list.update(node, 10);
list.printList();
cout << "测试getNode函数(正常位置)...\n";
Node<Student> stu1=list.getNode(2);
cout << stu1.data;
cout << "测试getNode函数(越界测试)...\n";
Node<Student> stu2 = list.getNode(10);
cout << stu2.data;
return 0;
}