【SEU程序设计课笔记】 26 - 2021/01/11 - Write C++ programs - 链表(List 类)

这篇博客介绍了一个模板类`List`的实现,它支持多种数据结构(如数组、向量、列表和双端队列)的构造,并提供了包括插入、删除、访问和打印等操作。此外,代码中包含了错误检查,当操作超出范围或尝试操作空链表时,会显示错误信息。
摘要由CSDN通过智能技术生成

链表

功能

公有函数功能
List(const List<T>&)拷贝构造函数
List(const T*, std::size_t)由数组构造
List(const std::vector<T>&)由 vector 构造
List(const std::list<T>&)由 list 构造
List(const std::deque<T>&)由 deque 构造
inline void push_back(const T& item)最后插入
inline void push_front(const T& item)最前插入
inline void pop_back()删除最后一个
inline void pop_front()删除第一个
inline void insert(const T& item, std::size_t index = node_number)在特定位置前插入
inline void removeAt(std::size_t index)删除特定位置的一个数
inline void clear()清空 List
inline void append(const List<T>&)List 后附加一个 List
inline bool isEmpty() const判断是都为空
inline T at(std::size_t index) const只读访问特定位置内容
inline T& at(std::size_t index)可写访问特定位置内容
std::size_t size() constList大小
void print(std::ostream& out = std::cout, std::string str = " ", bool null_info = false) const打印List(第一个参数:输出形式;第二个参数:间隔符;第三个参数:List为空是否提醒)
void operator=(const List<T>&);赋值
inline T operator[](std::size_t index) const;只读访问特定位置内容
inline T& operator[](std::size_t index);可写访问特定位置内容

输出:默认是print(out, " ");

代码

List.h

#pragma once
#include <iostream>
#include <string>
#include <vector>
#include <list>
#include <deque>
#include <Windows.h>
#define _LIST_H_

template<typename T0>
struct Node
{
	T0 value = 0;             // the value the node holds
	Node<T0>* next = nullptr; // the pointer that points to the next node

	Node() = default;         // the default constuctor 
	Node(T0 value_, Node<T0>* next_ = nullptr) : value(value_), next(next_) {} // constructor
};

template<typename T>
class List
{
public:
	List() = default;
	List(const List<T>&);
	List(const T*, std::size_t);
	List(const std::vector<T>&);
	List(const std::list<T>&);
	List(const std::deque<T>&);
	inline void push_back(const T& item);
	inline void push_front(const T& item);
	inline void pop_back();
	inline void pop_front();
	inline void insert(const T& item, std::size_t index = node_number);
	inline void removeAt(std::size_t index);
	inline void clear();
	inline void append(const List<T>&);
	inline bool isEmpty() const;
	inline T at(std::size_t index) const;
	inline T& at(std::size_t index);
	std::size_t size() const;
	void print(std::ostream& out = std::cout, std::string str = " ", bool null_info = false) const;
	void operator=(const List<T>&);
	inline T operator[](std::size_t index) const;
	inline T& operator[](std::size_t index);

private:
	Node<T>* head = nullptr;
	Node<T>* tail = head;
	std::size_t node_number = 0;

	inline Node<T>* find(std::size_t index);
};

template<typename T>
std::ostream& operator<<(std::ostream&, const List<T>& list);

template<typename T>
List<T>::List(const List<T>& new_list)
{
	for (Node<T>* p = new_list.head; p; p = p->next)
	{
		this->push_back(p->value);
	}
}

template<typename T>
List<T>::List(const T* new_elements, std::size_t new_size)
{
	for (std::size_t i = 0; i != new_size; i++)
	{
		this->push_back(*(new_elements++));
	}
}

template<typename T>
List<T>::List(const std::vector<T>& vec)
{
	for (T item : vec)
	{
		this->push_back(item);
	}
}

template<typename T>
List<T>::List(const std::list<T>& new_list)
{
	for (auto item : new_list)
	{
		this->push_back(item);
	}
}

template<typename T>
List<T>::List(const std::deque<T>& vec)
{
	for (T item : vec)
	{
		this->push_back(item);
	}
}

template<typename T>
void List<T>::push_back(const T& item)
{
	Node<T>* new_tail = new Node<T>(item);
	if (this->isEmpty())
	{
		tail = head = new_tail;
		node_number++;
	}
	else
	{
		tail->next = new_tail;
		tail = new_tail;
		node_number++;
	}
}

template<typename T>
void List<T>::push_front(const T& item)
{
	Node<T>* new_head = new Node<T>(item, head);
	this->head = new_head;
	node_number++;
}

template<typename T>
void List<T>::pop_back()
{
	if (!this->isEmpty())
	{
		if (node_number == 1)
		{
			node_number = 0;
			head = tail = nullptr;
		}
		else
		{
			find(node_number - 2)->next = nullptr;
			this->tail = find(node_number - 2);
			node_number--;
		}
	}
	else
	{
		MessageBox(NULL, L"Can not pop back an empty list.\nThis action has been omitted", L"ERROR", MB_ICONERROR);
	}
}

template<typename T>
void List<T>::pop_front()
{
	if (!this->isEmpty())
	{
		head = head->next;
		node_number--;
	}
	else
	{
		MessageBox(NULL, L"Can not pop front an empty list.\nThis action has been omitted", L"ERROR", MB_ICONERROR);
	}
}

template<typename T>
void List<T>::insert(const T& item, std::size_t index)
{
	if (index > node_number)
	{
		MessageBox(NULL, L"Can not insert out of range.\nThis action has been omitted", L"ERROR", MB_ICONERROR);
	}
	else
	{
		if (index)
		{
			Node<T>* new_node = new Node<T>(item, find(index));
			find(index - 1)->next = new_node;
			node_number++;
		}
		else
		{
			this->push_front(item);
		}
	}
}

template<typename T>
void List<T>::removeAt(std::size_t index)
{
	if (index >= node_number)
	{
		MessageBox(NULL, L"Can not remove out of range.\nThis action has been omitted", L"ERROR", MB_ICONERROR);
	}
	else if (index)
	{
		find(index - 1)->next = find(index + 1);
		node_number--;
	}
	else
	{
		pop_front();
	}
}

template<typename T>
void List<T>::clear()
{
	tail = head = nullptr;
	node_number = 0;
}

template<typename T>
bool List<T>::isEmpty() const
{
	if (node_number) return false;
	else return true;
}

template<typename T>
void List<T>::append(const List<T>& new_list)
{
	for (Node<T>* p = new_list.head; p; p = p->next)
	{
		this->push_back(p->value);
	}
}

template<typename T>
T List<T>::at(std::size_t index) const
{
	Node<T>* ret = find(index);
	if (ret)
	{
		return ret->value;
	}
	else
	{
		MessageBox(NULL, L"Subscript out of range.", L"ERROR", MB_ICONERROR);
		exit(-1);
	}
}

template<typename T>
T& List<T>::at(std::size_t index)
{
	Node<T>* ret = find(index);
	if (ret)
	{
		return ret->value;
	}
	else
	{
		MessageBox(NULL, L"Subscript out of range.", L"ERROR", MB_ICONERROR);
		exit(-1);
	}
}

template<typename T>
std::size_t List<T>::size() const
{
	return node_number;
}

template<typename T>
Node<T>* List<T>::find(std::size_t index)
{
	if (index > node_number)
	{
		return nullptr; // indecate can not find (i.e. not within range)
	}
	else
	{
		Node<T>* target = this->head;
		for (int i = 0; i != index; i++)
		{
			target = target->next;
		}
		return target;
	}
}

template<typename T>
void List<T>::print(std::ostream& out, std::string fill_str, bool null_info) const
{
	if (null_info && this->isEmpty())
	{
		MessageBox(NULL, L"Empty List", L"Information", MB_ICONINFORMATION);
		return;
	}
	Node<T>* p = this->head;
	for (; p && p->next; p = p->next)
	{
		out << p->value << fill_str;
	}
	if (p) out << p->value;
}

template<typename T>
void List<T>::operator=(const List<T>& new_list)
{
	this->clear();
	for (Node<T>* p = new_list.head; p; p = p->next)
	{
		this->push_back(p->value);
	}
}

template<typename T>
T List<T>::operator[](std::size_t index) const
{
	return this->at(index);
}

template<typename T>
T& List<T>::operator[](std::size_t index)
{
	return this->at(index);
}

template<typename T>
std::ostream& operator<<(std::ostream& out, const List<T>& list)
{
	list.print(out, " ");
	return out;
}

测试

测试代码:

#include "List.h"
using  namespace std;

int main(int argc, char** argv)
{
	double a[5] = { 0, 2, 3.4,-2, 0.8 };
	vector<double> b = { 0.1, -0.5, 0.3 };
	List<double> test(a, 4);
	List<double> test2(b);
	cout << test << endl;
	test.push_back(1);
	cout << test << endl;
	test.push_front(-6.2);
	cout << test << endl;
	test.removeAt(2);
	cout << test << endl;
	test.append(test2);
	cout << test << endl;
	test.pop_back();
	cout << test << endl;
	test[1] = -100;
	cout << test << endl;
	test.clear();
	cout << test << endl;
	for (size_t i = 0; i != 10; i++)
	{
		test.push_back(i);
	}
	cout << test << endl;
	test.insert(0, 3);
	cout << test << endl;
	for (size_t j = 0; j != 5; j++)
	{
		test.pop_front();
	}
	cout << test << endl;
	test = test2;
	test.print(cout, " -> ");
	cout << endl;
	return 0;
}

输出效果:
Output

分析

  • 本程序对于错误的操作进行了判断,并会用MessageBox弹窗提示。
  • 有一些奇怪的事情,如果将.h.cpp分离,编译器汇报奇怪的错误(MSVC 和 MinGW 都会):
    Error

ALL RIGHTS RESERVED © 2021 Teddy van Jerry
欢迎转载,转载请注明出处。


See also

Teddy van Jerry 的导航页

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值