【数据结构】单链表(Singly Linked List ) && 静态链表(Static list)

本文探讨了数据结构中的单链表和静态链表。单链表是一种动态存储结构,插入和删除操作相对简单。静态链表则是利用数组存储,每个元素包含数据域和指针域,指针域存储数组下标。文章详细解释了两种链表的存储结构、插入和删除操作的实现,并提供了C++的类模板实现。
摘要由CSDN通过智能技术生成

更多精彩尽在微信公众号【程序猿声】

微信公众号

数据结构-线性表|顺序表|链表(中)

本节纲要

  • 预备知识
  • 顺序表(Sequential List)
  • 单链表(Singly Linked List )
  • 静态链表(Static list )
  • 循环链表(circular linked list)
  • 双向链表(doubly linked list)

03 单链表(Singly Linked List )

3.1 什么是单链表?

单链表是一种链式存储的结构。它动态的为节点分配存储单元。当有节点插入时,系统动态的为结点分配空间。在结点删除时,应该及时释放相应的存储单元,以防止内存泄露。由于是链式存储,所以操作单链表时,必须知道头结点或者头指针的位置。并且,在查找第i个节点时,必须找到第i-1个节点。

3.2 单链表的存储结构代码描述

对于链式存储,通过上一节的讲解相信大家已经了解得够清楚了。如下图所示:

下面我们来看看单链表存储是如何用代码来实现的。

//单链表的存储结构C语言代码
typedef struct SListNode
{
    datatype data;    //数据域
    struct SListNode * pnext;//指针域
}SLinkList;

由上面的结构我们可以看出,一个节点由存放数据的数据域和存放地址的指针域组成。假如p指向了第i个节点,那么p->data就是该节点存放的数据,而p->pnext自然就是指向下一个节点的指针。如下图所示:

那么接下来我们看看单链表的各个操作具体实现吧。(只讲几个关键步骤)
备注:下面的代码基于这样的一个单链表:

  • 有一个头指针phead
  • 有一个头结点node
  • 头指针指向头结点,头结点位置记为0

3.3 单链表的读取

在拿到头指针以后,单链表的读取也并非一件难事。一开始设置一个计数变量,不断遍历链表,让计数器自增。找到合适的位置将数据读取出来。具体代码实现如下:

#define status bool
#define ERROR false
#define OK true
/*
 * 函数功能:获取位置index节点的数据
 * 参数说明:phead链表头结点,e用来获取的变量,index索引
*/

status GetSListIndexNode(Node * phead,DType *e, int index)
{
	int icount = 0; //计数器
    //注:0号位为头结点,头结点不存放任何数据
	if (phead->pnext == nullptr || index < 1 || index > GetSListLength()/*此处为链表长度*/)
	{
		return ERROR; //异常 处理
	}
	while (phead->pnext != nullptr)
	{
		icount++;
		phead = phead->pnext;
		if (icount == index)
		{
			*e = phead->data;
			return OK;
		}
	}
	return ERROR;
}

3.4 单链表的插入

3.4.1 指定位置后插

其实链表的插入和删除都是很简单的操作,初学者只要抓住指针指向的节点,并加以区分开来,就很easy了。如下图:

图中,假如此时p指向了我们要插入的节点的位置。那么,怎样把我们的S节点给插入到p指向的节点之后?在这里我们先不要惊动p以及p后面的节点:

  1. 我们先让S节点指向p之后的节点(步骤①)
  2. 之后我们切断p和p后面那个节点的关系(步骤②)
  3. 最后让p节点的指针域指向s节点(步骤③),搞定

算法描述:

  1. 声明一个指针p指向链表头结点,向后遍历p=p->next,找到正确的位置。
  2. 新建一个结点s。
  3. s->next = p->next ①
  4. p->next = s ②③
    具体代码如下:
#define status bool
#define ERROR false
#define OK true
/*
 * 函数功能:指定位置后插
 * 参数说明:phead链表头结点,IData插入的数据,index索引
*/
status InsertSListNodeFront(Node * phead, DType IData, int index)
{
	if (phead->pnext == nullptr || index < 1 || index > GetSListLength())
	{
		return ERROR; //异常 处理
	}
	int iCount = 0; //计数器
	Node<DType> * q = nullptr; //备用
	while (phead->pnext != nullptr)
	{
		iCount++;
		q = phead;
		phead = phead->pnext;
		if ( iCount == index )
		{
			Node<DType> * p = new Node<DType>;
			p->data = IData;
			p->pnext = phead;
			q->pnext = p;   //前插
			return OK;
		}
	}
	return ERROR;
}
3.4.1 指定位置前插

咳咳,聪明的小伙伴,用脑子想想。指定位置前插 == 指定位置的前一个位置进行后插。懂了吧?直接看具体代码:

/*
 * 函数功能:指定位置后插
 * 参数说明:phead链表头结点,IData插入的数据,index索引
*/
status InsertSListNodeBack(Node * phead, DType IData, int index)
{
	if (phead->pnext == nullptr || index < 1 || index > GetSListLength())
	{
		return ERROR; //异常 处理
	}
	int iCount = 0; //计数器
	Node<DType> * q = nullptr; //备用
	while (phead->pnext != nullptr)
	{
		iCount++;
		q = phead;
		phead = phead->pnext;
		if (iCount == index)
		{
			Node<DType> * p = new Node<DType>;
			q = phead;
			phead = phead->pnext; //后插就是后一个节点的前插咯
			p->data = IData;
			p->pnext = phead;
			q->pnext = p;   
			return OK;
		}
	}
	return ERROR;
}

3.5 单链表的删除

单链表的删除其实也是很简单。只要比如要删除p指向的节点,只需要让p之前的节点的指针域直接指向p之后的节点,再把p给free就OK了。如下图:

算法描述:

  1. 声明一个指针p指向链表头结点,向后遍历p=p->next,找到要删除的节点位置。
  2. q = p->next
  3. p->next = q->next ①②
  4. free(q) ③④

具体代码如下:

/*
 * 函数功能:指定位置后插
 * 参数说明:phead链表头结点,IData获取删除的数据,index索引
*/
//删除指定位置节点(e获取删除元素)
template <typename DType>
status DeleteSListIndexNode(Node * phead, DType *e, int index)
{
	int i = 0; //计数器
	Node<DType> * q = nullptr;
	if (phead->pnext == nullptr || index < 1 || index > GetSListLength())
	{
		return ERROR; //异常 处理
	}
	while (phead->pnext != nullptr)
	{
		i++;
		q = phead; //保存备用
		phead = phead->pnext;
		if (i =
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值