我的学习笔记(一):LinkedList在c++中的实现

今天是中秋节,开学第三周周末了,这学期让我感觉最有趣的课是python和数据结构,数据结构的前几节课,老师讲了list链表的两种实现方式,分别是Arraybased List和LinkedList。我感觉了解数据结构的底层实现方式特别有趣,于是课下自己花了两天的课余时间尝试了LinkedList的实现,在这里分享一下自己的心得。

一. 简介

List, 是一个由多个结点连接而成的链表,像一个火车一样,由一节一节的车厢组成,每个车厢仅仅连接前后相邻的车厢,有了这样的连接,火车头就可以带着多节车厢一起前进。List是一个可增可删,可以在任意位置插入的结构,与固定大小的数组相比,更加便于实际操作。本文主要介绍LinkedList在c++中的实现。
在这里插入图片描述

二. Link

有了链表的基本概念,那么火车厢之间是如何连接在一起的呢?很简单,就是指针。每一个结点都储存有两个值:结点本身的数值和下一个结点的位置。所以我们只要做如下的定义:

template <class Elem> class Link {
public:
	Elem element;
	Link *next;

	Link<Elem>(const Elem& value, Link<Elem>* nextval = nullptr)
		:element(value),next(nextval)
	{
	}

	Link<Elem>(Link<Elem>* nextval = nullptr) 
		:next(nextval)
	{
	}
};

我们当然不希望这个链表只能储存整数或者只能储存字符,所以我们将Link定义为模板类,Elem代表各种数据类型,如int,float,char,string……
另外,在这里我们要讲一下list和array的一个重要区别list的元素的储存位置是分散的,而array的储存位置是连续的。
Array在初始化时,系统根据数组的大小分配了一块连续的储存区域,数组的大小再也不可以改变,这也正是array不能直接往数组中间插入数值的原因;
对于list,初始化时仅仅生成了第一个位置(也就是火车头),每次增加元素时,系统单独分配一个内存空间给这个新元素,相邻位置的元素会储存下这个新元素的内存地址(也就是Link类中的*next),所以,即使list的储存空间是分散的,仍然可以通过这些储存下的地址找到list中的元素。

三. 定义LinkedList类

有了Link这个基础的结构,我们就可以搭建LinkedList类了,给火车装上发动机,给火车上的工作人员分配好具体工作,保证火车稳定的开动。先来看看private的数据成员和初始化函数:

#include "Link.h"
class LinkedList :
{
private:
	Link<Elem>* head;
	Link<Elem>* tail;
	Link<Elem>* fence;
	int leftnum;
	int rightnum;
public:
	LinkedList() {
		head = tail = fence = new Link<Elem>;
		leftnum = 0;
		rightnum = 0;
	}
}

很直观,head是链表的第一个位置,tail是链表的最后一个位置,fence则代表当前位置,leftnum和rightnum代表当前位置前后的元素的数量。初始化一个list,没有传入元素,初始化后如图所示,如果没有看懂可以回顾一下上面Link类的初始化哦
在这里插入图片描述
有了这几个基础的数据成员,我们就可以实现大部分list链表的操作了。看,我们要实现的函数有,这么多!别怕,熟悉了基本的操作,就能举一反三了。

	void clear();	//清空所有数据
	
	bool insert(const Elem&);	//在当前位置插入数据
	
	bool append(const Elem&);	//在链表尾部增加元素
	
	bool remove();	//移除当前位置元素
	
	void setStart();	//将当前位置设定为第一个位置
	
	void setEnd();	//将当前位置设定为最后一个位置
	
	void prev();	//将位置向前移一位
	
	void next();	//将位置向后移一位
	
	int leftLength() const;	//返回前面的元素数量
	
	int rightLength() const;	//返回后面元素数量
	
	bool setPos(int pos);	//设置当前位置
	
	bool getValue(Elem&) const;	//获取当前的数值
	
	void print() const;	//打印整个链表
	

四.函数实现

先来看看insert函数的实现,不如再看一次初始化实例图:
在这里插入图片描述
1.当我们为链表插入第一个元素时的步骤是这样的:

a)先创建一个element为73,指向null的一个Link对象:

Link<int>* temp=new Link<int>(73,nullptr);

b)原本fence是指向null的,我们要让它指向这个新元素temp:

fence->next=temp;

c)然后,右边元素数加一,tail相应地要移到73的位置,如图

tail=temp;
rightnum++;

在这里插入图片描述

2.插入第一个元素之后,我们想要在fence处再插入一个数72:
a)同样地创建一个值为72的Link对象,但是需要注意的是,此时不是在队尾插入,而是在fence和tail之间插入,所以我们不能像刚才一样让新建的Link指向null,而是应该指向下一个,即73

Link<int>* temp=new Link<int>(72,fence->next);

b)fence指向72,和上面一样,tail仍然是73,无需修改:

fence->next=temp;
rightnum++;

在这里插入图片描述
3.经过上面两个例子,我们可以整理为通用的insert函数:

	bool insert(const Elem& val) { 
		fence->next = new Link<Elem>(val, fence->next);
		if (fence == tail) {
			tail = fence->next;
		}
		rightnum++;
		return true; 
	}

4.append函数也就可以实现了:

bool append(const Elem& val) {
		tail->next = new Link<Elem>(val, nullptr);
		tail = tail->next;
		//也可以直接赋值: tail=tail->next=new Link<Elem>(val,nullptr);
		rightnum++;
		return true;
	}

好了,详细介绍了insert函数之后,其他函数也不难实现了,我觉得完整代码直接放在文章里面显得太臃肿了,有需要的百度云自取:链接:https://pan.baidu.com/s/1RXCwgPrdvhuoRIPRb01GKQ 提取码:a8uy 。如果有问题可以在评论区讨论,有错误也烦请指正,谢谢!

  • 4
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值