C++实现单链表(1)
1、什么是单链表?
逻辑结构上一个挨一个的数据,在实际存储时,数据随机分布在内存中的各个位置,这种存储结构称为线型表的链式存储。
由于分散存储,为了能够体现出数据元素之间的逻辑关系,每个数据元素在存储的同时,要配备一个指针,用于指向它的直接后继元素,即每一个数据元素都指向下一个数据元素(最后一个指向NULL(空))。
链表中每个元素都被称为结点,结点由数据域以及指针域构成,如下图:
2、结点的C++实现
由于结点中的数据域与指针域类型不一致,我们可以使用结构体作为结点的类型,同时数据域中的数据类型也是不确定的,可以使用模板技术。
#pragma once
//Node.h文件
template<typename Datatype>
struct Node
{
Datatype Data; //结点数据域
Node<Datatype>* next; //结点指针域
};
3、头指针及头结点
有时,在链表的第一个结点之前会额外增设一个结点,结点的数据域一般不存放数据(有些情况下也可以存放链表的长度等信息),此结点被称为头结点。
指向头结点的指针称为头指针。
4、创建LinkList类,成员函数定义和声明统一放在LinkList.hpp文件中
template<typename Datatype>
class LinkList
{
public:
LinkList();
~LinkList();
LinkList(Datatype Array[], int Array_length);
const Datatype& Get(int Location)const;
int Length();
bool IsEmpty();
void Insert(const Datatype& insert_data, int insert_location);
void Delete(int delet_location);
void Reverse();
void Empty();
void PrintList();
private:
Node<Datatype>* first; //头指针
};
5、默认构造
对于链表的默认构造,主要就是使用new为头结点分配堆内存空间,并将头指针指向头结点,并初始化头结点指针域。
template<typename Datatype>
inline LinkList<Datatype>::LinkList()
{
this->first = new Node<Datatype>;
this->first->next = nullptr;
}
6、带参构造
支持传递一个数组,并将数组中的元素按对应的顺序组成一个链表。这里必须传递数组的大小,具体原因在数组指针,指针数组这里已经分析过了。
//头插法
template<typename Datatype>
inline LinkList<Datatype>::LinkList(Datatype Array[], int Array_length)
{
//初始化头结点
this->first = new Node<Datatype>;
this->first->next = nullptr;
//从后往前遍历依次插入在头结点之后,保证数组顺序与链表顺一致
for (int i = Array_length - 1; i >= 0; i--)
{
//初始化待插入结点
Node<Datatype>* s = new Node<Datatype>;
s->Data = Array[i];
s->next = this->first->next;
//头结点指针域指插入结点
this->first->next = s;
}
}
7、获取链表指定位置的元素
template<typename Datatype>
inline const Datatype& LinkList<Datatype>::Get(int Location) const
{
int count = 1;
//p初始化为头结点的指针域
Node<Datatype>* p = this->first->next;
while (nullptr != p && count < Location)
{
count++;
p = p->next;
}
/**
* 结束循环的条件:
* 1、p指向查找的元素
* 2、p为尾结点的指针域,指向nullptr
*/
if (nullptr == p) throw "数据不存在";
return p->Data;
}
8、计算链表长度
template<typename Datatype>
inline int LinkList<Datatype>::Length()
{
int count = 0;
Node<Datatype>* p = this->first->next;
while (nullptr != p)
{
count++;
p = p->next;
}
return count;
}
9、判断链表是否为空
template<typename Datatype>
inline bool LinkList<Datatype>::IsEmpty()
{
if (nullptr == this->first->next) return true;
return false;
}
10、链表遍历
template<typename Datatype>
inline void LinkList<Datatype>::PrintList()
{
Node<Datatype>* p = this->first->next;
while (nullptr != p)
{
cout << p->Data;
p = p->next;
}
cout << endl;
}
11、清空链表,记得同时释放堆内存
template<typename Datatype>
inline void LinkList<Datatype>::Empty()
{
Node<Datatype>* p = this->first->next, * s = nullptr;
while (nullptr != p)
{
s = p->next;
delete p;
p = s;
}
//头结点指针域指向nullptr
this->first->next = nullptr;
}
12、析构函数中同样记得需要释放堆内存
template<typename Datatype>
inline LinkList<Datatype>::~LinkList()
{
this->Empty();
delete this->first;
}
13、测试代码
#include <iostream>
#include <string>
#include "LinkList.hpp"
using namespace std;
int main()
{
string string_array[] = { "This ", "is ", "string_list ", "test." };
//使用带参构造数据域为string类型的链表
LinkList<string>* list_string_p = new LinkList<string>
(string_array, sizeof(string_array) / sizeof(string_array[0]));
try
{
list_string_p->PrintList();
cout << "string链表第4个元素:" << list_string_p->Get(4) << endl;
list_string_p->Empty();
cout << list_string_p->Length() << endl;
}
catch (const char* catch_string)
{
cout << catch_string << endl;
}
delete list_string_p;
system("pause");
return 0;
}
执行结果
新人才疏学浅,有错的地方敬请指正!!
本文来自博客园,作者:夏末终年,转载请注明出处:https://www.cnblogs.com/xiamozhongnian/p/15857385.html