[朝花夕拾]单链表篇-C++

本文详细介绍了一种基于C++的单链表实现方法,包括结构定义、基本操作如添加、删除、更新节点等,并通过具体示例展示了如何使用自定义的单链表类进行数据操作。此外,还提供了完整的源代码和测试函数,帮助读者理解和实践。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

[朝花夕拾]单链表篇-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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值