[朝花夕拾]單鏈表篇-C++

[朝花夕拾]單鏈表篇-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;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章