数据结构【链表及其相关操作】

1. 什么是链表,链表的分类?

链表是一种物理存储结构上非连续、非顺序的存储结构,数据元素的逻辑顺序是通过链表中的指针链接次序是实现的
链表的结构有很多,以下情况组合起来就有8种链表结构:
单向、双向;带头、不带头;循环、非循环
我们在实际中最常用的有两种结构:无头单向非循环链表(结构简单)和带头双向循环链表(结构最复杂)

2. 链表带头结点和不带头结点有什么区别?

数据结构中,链表分为有头结点和无头节点
头结点:在单链表的第一个节点之前设置一个节点,它没有直接前驱,被称为头结点。 头结点的数据域不存储任何信息,指针域指向链表的第一个节点
头指针:头指针是指向链表中第一个节点的指针,链表中可以没有头结点,但是一定不能没有头指针。在有头节点的链表中,头指针指向的是头结点
链表有头结点和无头节点就直接导致了对链表的基本操作的不同
因为有了头节点,不管链表是否为空,链表(包括空表)的头指针一定是非空的,这就使对链表中第一个位置的操作与其他位置的操作一致,更加方便。

3. 单链表的基本操作(有头节点)

1.链表的节点

typedef int SDataType;

// 链表的节点
typedef struct SListNode
{
	SDataType _data;
	struct  SListNode* _pNext;
}Node, *PNode;

2.链表的结构
给一个头指针保存链表第一个节点的地址

typedef struct SList
{
	PNode _pHead;   // 指向链表中的第一个节点
}SList, *PSList;

3. 链表的初始化

void SListInit(SList* s)
{
	assert(s);
	s->_pHead = NULL;
}

4.链表的尾插

//在链表s最后一个节点后插入一个值为data的新节点 
void SListPushBack(SList* s, SDataType data)
{
	assert(s);
	PNode pNewNode = BuySListNode(data);
	if (NULL == s->_pHead)
	{
		// 空链表
		s->_pHead = pNewNode;
	}
	else
	{
		// 链表非空
		// 找链表中最后一个节点
		PNode pCur = s->_pHead;
		while (pCur->_pNext)
			pCur = pCur->_pNext;


		pCur->_pNext = pNewNode;
	}
}

5.链表的尾删

//删除链表s最后一个节点
void SListPopBack(SList* s)
{
	assert(s);
	if (NULL == s->_pHead)  // 空链表
		return;
	else if (NULL == s->_pHead->_pNext) // 只有一个节点
	{
		free(s->_pHead);
		s->_pHead = NULL;
	}
	else
	{
		// 多个节点
		PNode pPre = NULL;
		PNode pCur = s->_pHead;
		while (pCur->_pNext)
		{
			pPre = pCur;
			pCur = pCur->_pNext;
		}

		free(pCur);
		pPre->_pNext = NULL;
	}
}

6.链表的头插

//在链表s第一个节点前插入值为data的节点 
void SListPushFront(SList* s, SDataType data)
{
	assert(s);
	PNode pNewNode = BuySListNode(data);
	pNewNode->_pNext = s->_pHead;
	s->_pHead = pNewNode;
}

7.链表的头删

//删除链表s的第一个节点 
void SListPopFront(SList* s)
{
	PNode pDelNode = NULL;
	assert(s);
	if (NULL == s->_pHead)
		return;
	// 找到待删除的节点
	pDelNode = s->_pHead;
	s->_pHead = pDelNode->_pNext;
	free(pDelNode);
}

8.在链表的任意位置插入节点

//在链表的pos位置后插入值为data的节点 
void SListInsert(PNode pos, SDataType data)
{
	if (NULL == pos)
		return;
	PNode pNewNode = NULL;
	pNewNode = BuySListNode(data);
	pNewNode->_pNext = pos->_pNext;
	pos->_pNext = pNewNode;
}

9. 删除链表s中pos位置的节点

void SListEarse(SList* s, PNode pos) {
	assert(s);
	if (NULL == pos || NULL == s->_pHead) {
		return;
	}
	if (pos == s->_pHead) {
		s->_pHead = s->_pHead->_pNext;
	}
	else{
		PNode pPrePos = s->_pHead;
		while (pPrePos && pPrePos->_pNext != pos)
			pPrePos = pPrePos->_pNext;

		if (pPrePos)
			pPrePos->_pNext = pos->_pNext;
	}
	free(pos);
}

10.在链表中查找值为data的节点,找到返回该节点的地址,否则返回NULL

PNode SListFind(SList* s, SDataType data) {
	assert(s);
	PNode pCur = s->_pHead;
	while (pCur) {
		if (pCur->_data == data) {
			return pCur;
		}	
		pCur = pCur->_pNext;
	}
	return NULL;
}

11. 获取链表中有效节点的个数

int SListSize(SList* s)
{
	assert(s);
	PNode pCur = s->_pHead;
	size_t count = 0;
	while (pCur)
	{
		count++;
		pCur = pCur->_pNext;
	}

	return count;
}

12.检测链表是否为空

int SListEmpty(SList* s)
{
	assert(s);
	return NULL == s->_pHead;
}

13.将链表中有效节点清空

// 将链表中有效节点清空 
void SListClear(SList* s) {
	assert(s);
	while (SListSize(s)) {
		SListPopBack(s);
	}
	free(s->_pHead);
}

14.销毁链表

void SListDestroy(SList* s) {
	assert(s);
	while (SListSize(s)) {
		SListPopBack(s);
	}
	free(s->_pHead);
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值