数据结构 | 单链表的基本实现

学习教材:《数据结构——从概念到C++实现》
分类专栏:数据结构与算法(C++)

目录

前言

全文

1 链表概述

2 单链表的基本实现

2.1 建立只有头结点的空链表

2.2 建立指定长度的链表

2.3 析构函数

2.4 求单链表长度

2.5 按位查找元素

2.6 按值查找元素,返回元素序号

2.7 插入操作

2.8 删除操作

2.9 判空操作

2.10 遍历操作

全部代码

前言

        最近刚在学习《数据结构与算法》,单纯地跟课、看书觉得并不能很好的掌握好这些知识点,所以决定尝试将学习的知识点归纳总结,也将其进行代码实现,强化对知识点的理解。即作为笔记、实践,又作为我的思路分享。因为初学,难免有不正确、不恰当之处,敬请指正!

全文

1 单链表概述

        单链表(singly linked list)是用一组任意的存储单元存放线性表的元素,这组存储单元可以连续也可以不连续,甚至可以零散分布在内存中的任意位置。

        结点(node)是存放了数据元素和其后续元素所在的地址信息的存储映像。其中。data为数据域,存放数据元素;next为指针域,存放该结点的后继结点的地址。

        单链表通过每个结点的指针域将线性表的数据元素按照其逻辑次序链接在一起,由于每个结点只有一个指针域,故称为单链表。

2 单链表的基本实现

        先定义单链表的结点结构,包括数据域和指针域。

template<typename DataType>
struct Node
{
	// 数据域
	DataType data;
	// 指针域
	Node<DataType>* next;
};

        定义单链表类,其中成员变量 first 表示单链表的头指针,成员函数实现线性表的基本操作。

template<typename DataType>
class LinkList
{
public:
	// 建立只有头节点的空链表
	LinkList(); 
	// 建立n个元素的单链表
	LinkList(DataType a[], int n); 
	// 析构函数
	~LinkList() {};
	// 求单链表长度
	int Length();
	// 按位查找元素
	DataType Get(int i);
	// 按值查找元素,返回元素序号
	int Locate(DataType x);
	// 插入操作,在第i个位置插入值为x的元素
	void Insert(int i, DataType x);
	// 删除操作,删除第i个元素
	DataType Delect(int i);
	// 判断是否为空表
	int Empty();
	// 遍历单链+表进行打印
	void printList(); 

private:
	Node<DataType>* first; // 头指针
};

2.1 建立只有头结点的空链表

        初始化单链表就是生成只有头结点的空单链表。

// 建立只有头节点的空链表
template<typename DataType>
LinkList<DataType>::LinkList()
{
	first = new Node<DataType>;
	first->next = nullptr;
}

2.2 建立指定长度的链表

        本文中,选择采用头插法建立指定长度的链表。基本思想时将每次新申请的结点插在头结点的后面。

// 建立n个元素的单链表
template<typename DataType>
LinkList<DataType>::LinkList(DataType a[], int n)
{
	for (int i = 0; i < n; i++)
	{
		first = new Node<DataType>;
		first->next = nullptr;
		for (int i = 0; i < n; i++)
		{
			Node<DataType>* s = nullptr;
			s = new Node<DataType>;
			s->data = a[i];
			s->next = first->next;
			first->next = s;
		}
	}
}

2.3 析构函数

        单链表是动态存储分配,单链表的结点实在程序运行中动态申请的,因此在单链表变量退出作用域之前,要释放单链表的存储空间。

// 析构函数
template<typename DataType>
LinkList<DataType>::~LinkList()
{
	Node<DataType>* p = first;
	while (first != nullptr)
	{
		first = first->next;
		delete p;
		p = first;
	}
}

2.4 求单链表长度

        由于单链表类定义中没有存储线性表的长度,因此不能直接获得线性表的长度,使用遍历的方法来求其长度,设置工作指针p依次指向各个节点,当指针 p 指向一个结点时,累加器 count 加1,一直持续到最后一个结点,最后输出累加器 count 的值。

// 求单链表长度
template<typename DataType>
int LinkList<DataType>::Length()
{
	// 工作指针初始化
	Node<DataType>* p = first->next; 
	// 累加器初始化,算出链表长度
	int count = 0;
	while (p != nullptr)
	{
		p = p->next;
		count++;
	}
	return count;
}

2.5 按位查找元素

        单链表是随机存储结构,不能直接跟据访问结点的序号来获取数据,只能从头指针出发顺 next 域逐个结点往下搜素。设置工作指针p,当指针p指向某结点判断为第 i 个结点时,查找成功,输出数据元素。若 i 超出链表长度,则查找失败。

// 按位查找元素
template<typename DataType>
DataType LinkList<DataType>::Get(int i)
{
	// 工作指针初始化
	Node<DataType>* p = first->next;
	int count = 1;
	while (p != nullptr && count < i)
	{
		p = p->next;
		count++;
	}
	if (p == nullptr) throw"查找位置错误";
	else return p->data;
}

2.6 按值查找元素,返回元素序号

        在单链表中按值查找操作,需要对单链表中的元素依次进行比较。如果查找成功,返回元素的序号,否则返回0表示失败。

// 按值查找元素,返回元素序号
template<typename DataType>
int LinkList<DataType>::Locate(DataType x)
{
	// 工作指针初始化
	Node<DataType>* p = first->next;
	int count = 1;
	while (p != nullptr)
	{
		if (p->data == x)
			return count; // 查找成功返回序号 
		p = p->next;
		count++;
	}
	return 0; // 退出循环,表明查找失败
}

2.7 插入操作

        插入操作是将值为 x 的新结点插入到链表的第 i 个位置。需要先扫描单链表,找到原来第 i-1 个结点,然后生成一个新的结点s,将结点 s 的指针域指向原来第 i 个结点,在数据域中存储 x ,最后将结点 s 的地址信息存储到第 i-1 个结点的指针域中。 

// 插入操作,在第i个位置插入值为x的元素
template<typename DataType>
void LinkList<DataType>::Insert(int i, DataType x)
{
	// 工作指针初始化
	Node<DataType>* p = first->next, * s = nullptr;
	int count = 0;
	while (p != nullptr && count < i-1)
	{
		p = p->next;
		count++;
	}
	if (p == nullptr) throw"插入位置错误!";
	else
	{
		s = new Node<DataType>;
		s->data = x;
		s->next = p->next;
		p->next = s;
	}
}

2.8 删除操作

        删除操作是将第 i 个结点删去。需要找到第 i+1 个结点的存储地址,存储到第 i-1 个结点的指针域中,把第 i 个结点从恋上摘下,并通过 delete 释放其存储空间。

// 删除操作,删除第i个元素
template<typename DataType>
DataType LinkList<DataType>::Delect(int i)
{
	DataType x;
	// 工作指针初始化
	Node<DataType>* p = first->next, * s = nullptr;
	int count = 0;
	while (p != nullptr && count < i-1)
	{
		p = p->next;
		count++;
	}
	if (p == nullptr || p->next = nullptr ) throw"删除位置错误!";
	else
	{
		s = p->next;
		x = s->data;
		p->next = s->next;
		delete s;
		return x;
	}
}

2.9 判空操作

        判空操作只需要判断单链表是否只有头结点,即 first->next 是否为空指针。

// 判断是否为空表
template<typename DataType>
int LinkList<DataType>::Empty()
{
	if (first->next == nullptr)
	{
		return 0;
	}
	else return 1;
}

2.10 遍历操作

        遍历操作是指按序号依次访问单链表中所有的结点。可以设置一个工作指针p依次指向各个节点,当指针p指向某结点时,输出该结点的数据域。

// 遍历单链+表进行打印
template<typename DataType>
void LinkList<DataType>::printList()
{
	Node<DataType>* p = first->next;
	while (p != nullptr)
	{
		cout << p->data << " ";
		p = p->next;
	}
}

全部代码

#include<iostream>
#include<string>
using namespace std;

template<typename DataType>
struct Node
{
	// 数据域
	DataType data;
	// 指针域
	Node<DataType>* next;
};

template<typename DataType>
class LinkList
{
public:
	// 建立只有头节点的空链表
	LinkList(); 
	// 建立n个元素的单链表
	LinkList(DataType a[], int n); 
	// 析构函数
	~LinkList();
	// 求单链表长度
	int Length();
	// 按位查找元素
	DataType Get(int i);
	// 按值查找元素,返回元素序号
	int Locate(DataType x);
	// 插入操作,在第i个位置插入值为x的元素
	void Insert(int i, DataType x);
	// 删除操作,删除第i个元素
	DataType Delect(int i);
	// 判断是否为空表
	int Empty();
	// 遍历单链+表进行打印
	void printList(); 

private:
	Node<DataType>* first; // 头指针
};

// 建立只有头节点的空链表
template<typename DataType>
LinkList<DataType>::LinkList()
{
	first = new Node<DataType>;
	first->next = nullptr;
}

// 建立n个元素的单链表
template<typename DataType>
LinkList<DataType>::LinkList(DataType a[], int n)
{
	for (int i = 0; i < n; i++)
	{
		first = new Node<DataType>;
		first->next = nullptr;
		for (int i = 0; i < n; i++)
		{
			Node<DataType>* s = nullptr;
			s = new Node<DataType>;
			s->data = a[i];
			s->next = first->next;
			first->next = s;
		}
	}
}

// 析构函数
template<typename DataType>
LinkList<DataType>::~LinkList()
{
	Node<DataType>* p = first;
	while (first != nullptr)
	{
		first = first->next;
		delete p;
		p = first;
	}
}

// 求单链表长度
template<typename DataType>
int LinkList<DataType>::Length()
{
	// 工作指针初始化
	Node<DataType>* p = first->next; 
	// 累加器初始化,算出链表长度
	int count = 0;
	while (p != nullptr)
	{
		p = p->next;
		count++;
	}
	return count;
}

// 按位查找元素
template<typename DataType>
DataType LinkList<DataType>::Get(int i)
{
	// 工作指针初始化
	Node<DataType>* p = first->next;
	int count = 1;
	while (p != nullptr && count < i)
	{
		p = p->next;
		count++;
	}
	if (p == nullptr) throw"查找位置错误";
	else return p->data;
}

// 插入操作,在第i个位置插入值为x的元素
template<typename DataType>
void LinkList<DataType>::Insert(int i, DataType x)
{
	// 工作指针初始化
	Node<DataType>* p = first->next, * s = nullptr;
	int count = 0;
	while (p != nullptr && count < i-1)
	{
		p = p->next;
		count++;
	}
	if (p == nullptr) throw"插入位置错误!";
	else
	{
		s = new Node<DataType>;
		s->data = x;
		s->next = p->next;
		p->next = s;
	}
}

// 按值查找元素,返回元素序号
template<typename DataType>
int LinkList<DataType>::Locate(DataType x)
{
	// 工作指针初始化
	Node<DataType>* p = first->next;
	int count = 1;
	while (p != nullptr)
	{
		if (p->data == x)
			return count; // 查找成功返回序号 
		p = p->next;
		count++;
	}
	return 0; // 退出循环,表明查找失败
}

// 删除操作,删除第i个元素
template<typename DataType>
DataType LinkList<DataType>::Delect(int i)
{
	DataType x;
	// 工作指针初始化
	Node<DataType>* p = first->next, * s = nullptr;
	int count = 0;
	while (p != nullptr && count < (i-1))
	{
		p = p->next;
		count++;
	}
	if (p == nullptr || p->next == nullptr ) throw"删除位置错误!";
	else
	{
		s = p->next;
		x = s->data;
		p->next = s->next;
		delete s;
		return x;
	}
}

// 判断是否为空表
template<typename DataType>
int LinkList<DataType>::Empty()
{
	if (first->next == nullptr)
	{
		return 0;
	}
	else return 1;
}

// 遍历单链+表进行打印
template<typename DataType>
void LinkList<DataType>::printList()
{
	Node<DataType>* p = first->next;
	while (p != nullptr)
	{
		cout << p->data << " ";
		p = p->next;
	}
	cout << endl;
}

// 测试代码
//void test()
//{
//	int r[5] = { 2,4,3,5,6 };
//	int x = 0, i = 0;
//	LinkList<int> l(r, 5);
//	cout << "当前链表的数据为:";
//	l.printList();
//
//	l.Insert(2, 8);
//	cout << "插入后链表的数据为:";
//	l.printList();
//
//	cout << "当前链表的长度为: " << l.Length()<<endl;
//	cout << "请输入查找的元素值: ";
//	cin >> x;
//	i = l.Locate(x);
//	cout << x << "元素的位置为:" << i << endl;
//
//	cout << "请输入要删除的元素序号:" << endl;
//	cin >> i;
//	x = l.Delect(i);
//	cout << "删除的元素值为: " << x << endl;
//	cout << "删除后链表的数据为:";
//	l.printList();
//}

int main()
{
	//test();  测试代码
	return 0;
}

初学数据结构与算法,若有不正确之处,敬请指正啦~

  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值