单链表基本操作

今天我们主要研究单向无头单链表

先构建一个结点

typedef int DataType;


typedef struct SListNode {
DataType data; // 值 
struct ListNod* pNext; // 指向下一个结点 

} SListNode;


打印链表

void SListPrint(SListNode *pFirst)
{
	SListNode *pCur;
	for (pCur = pFirst; pCur != NULL; pCur = pCur->pNext)
	{
		printf("%d->", pCur->data);
	}
	printf("\n");
}


1、首先需要初始化单链表

//初始化
void SListInit(SListNode **ppFirst)
{
	assert(ppFirst != NULL);
	*ppFirst = NULL;
}

2、需要创建新的结点

//创建新结点
SListNode BuyNewNode(DataType data)
{
	SListNode* New;
	New= (SListNode*)malloc(sizeof(SListNode));
	assert(New != NULL);//申请完成后一定要判断是否申请到
	New->data = data;
	New->pNext = NULL;
	return *New;
}

3、尾插操作

尾插分为以下两种情况


// 尾部插入 
//1、链表为空
//2、链表不为空
void SListPushBack(SListNode** ppFirst, DataType data)
{
	assert(ppFirst != NULL);
	SListNode *New, *pNode = ppFirst;
	*New = BuyNewNode(data);
	assert(New!= NULL);
	if (NULL == *ppFirst)//链表为空直接在*ppFirst处插入就好
	{
		*ppFirst = New;
		return;
	}
	while(pNode->pNext)//尾插的时候需要找到倒数第一个结点,所以循环终止条件设为pNode->pNext!=NULL
	{
		pNode = pNode->pNext;
	}
	pNode->pNext = New;
}

4、头插

头插也分为两种情况


// 头部插入 
//1、链表为空
//2、链表中有元素
void SListPushFront(SListNode **ppFirst, DataType data)
{
	assert(ppFirst != NULL);
	SListNode *NewNode = NULL;
	NewNode = BuyNewNode(data);
	if (NULL == *ppFirst)//链表为空直接在*ppFirst处插入就好
	{
		*ppFirst = NewNode;
		return;
	}
	NewNode->pNext = *ppFirst;
	*ppFirst = NewNode;
}

5、尾删

尾删分三种情况


// 尾部删除 
//1、链表为空,直接返回
//2、只有一个结点,直接free后把ppFirst置空
//3、有多个结点,找到倒数第二个结点,free倒数第一个结点,把倒数第二个结点的pNext赋为空
void SListPopBack(SListNode **ppFirst)
{
	assert(ppFirst != NULL);
	if (NULL == *ppFirst)//情况1
	{
		return;
	}
	if (NULL == (*ppFirst)->pNext)//情况2
	{
		free(*ppFirst);
		*ppFirst = NULL;
		return;
	}
	SListNode *pDel, *pCur;
	for (pDel = *ppFirst; pDel->pNext->pNext != NULL; pDel = pDel->pNext)
	{
	}
	pCur = pDel;
	pDel = pDel->pNext;
	pCur->pNext = pDel->pNext;
	free(pDel);

}

6、头删

头删也分三种情况



// 头部删除 
//1、链表为空,直接返回
//2、只有一个结点,直接free后把ppFirst置空
//3、用pDel保存ppFirst的位置,然后ppFirst指向pNext然后free掉pDel
void SListPopFront(SListNode **ppFirst)
{
	assert(ppFirst != NULL);
	if (NULL == *ppFirst)//情况1
	{
		return;
	}
	if (NULL == (*ppFirst)->pNext)//情况2
	{
		free(*ppFirst);
		*ppFirst = NULL;
		return;
	}
	SListNode *pDel;
	pDel = *ppFirst;
	*ppFirst = pDel->pNext;
	free(pDel);
}

7、给定结点插入,插入到结点前 

需要考虑

链表是否存在,pos位置是否为空 

当pos位置不空时:如图示


// 给定结点插入,插入到结点前 
void SListInsert(SListNode **ppFirst, SListNode *Pos, DataType data)
{
	assert(ppFirst);
	if (Pos == *ppFirst)
	{
		SListPushFront(ppFirst,data);
		return;
	}
	SListNode *pNewNode = BuyNewNode(data);
	SListNode *pNode ;
	pNode = *ppFirst;
	while ((pNode) && (pNode->pNext != Pos))
	{
		pNode = pNode->pNext;
	}
	if (pNode == NULL)
	{
		printf("没找到该结点\n");
		return;
	}
	else
	{
		pNode->pNext = pNewNode;
		pNode->pNext->pNext = Pos;
		Pos = pNode->pNext;
	}
}

8.给定结点删除 
有以下几种情况
1、链表为空或者pos位置wei'k,直接返回
2、如果pos是第一个结点,直接调用头删函数

3、如果不是第一个结点


// 给定结点删除 
void SListErase(SListNode **ppFirst, SListNode *Pos)
{
	assert(ppFirst);
	if ((NULL != ppFirst) && (Pos == NULL))
	{
		return ;
	}
	if (Pos == *ppFirst)
	{
		*ppFirst = Pos->pNext;
		free(Pos);
		return;
	}
	SListNode *pNode = *ppFirst;
	while (pNode->pNext != Pos)
	{
		pNode = pNode->pNext;
	}
	pNode->pNext = Pos->pNext;
	free(Pos);

}


9.查找一个值为data的节点,如果存在,返回所在位置,否则,返回NULL 

只需要遍历一遍链表即可。 

// 按值查找,返回第一个找到的结点指针,如果没找到,返回 NULL 
SListNode* SListFind(SListNode *ppFirst, DataType data)
{
	assert(ppFirst);
	if (NULL != ppFirst)
	{
		return NULL;
	}
	SListNode *pCur = ppFirst;
	while (pCur){
		if (pCur->data = data)
		{
			return pCur;
		}
		pCur = pCur->pNext;
	}
	return NULL;

}

10、// 按值删除,只删遇到的第一个 


// 按值删除,只删遇到的第一个 
void SListRemove(SListNode **ppFirst, DataType data)
{
	assert(ppFirst);
	if (*ppFirst == NULL)
	{
		return;
	}
	SListNode *pCur;
	pCur = *ppFirst;
	while (pCur)
	{
		if (pCur->data = data)
		{
			SListErase(&ppFirst, pCur);
			return;
		}
		pCur = pCur->pNext;
	}
	if (pCur == NULL)
	{
		printf("没有该元素\n");
		return;
	}
}

11、删除所以值为data的结点

①第一个节点的值是data,因为删除第一个节点需要修改ppFirst的值,所以需要单独处理第一个节点的值是data的时候。 
删除第一个节点就是上面所说的头删。 
②如果第一个节点的值不是data,直接处理即可。 
下面处理第一个值不是data(这里的data为2)的情况:



// 按值删除,删除所有的 
void SListRemoveAll(SListNode **ppFirst, DataType _data)
{
	assert(ppFirst);
	if (NULL == *ppFirst)
	{
		return;
	}
	SListNode *pDel = *ppFirst;
	if ((*ppFirst)->data == _data)
	{
		*ppFirst = (*ppFirst)->pNext;
		free(pDel);
	}
	SListNode *pCur = *ppFirst;
	SListNode *prev = pCur;
	while (pCur)
	{
		if (pCur->data == _data)
		{
			prev->pNext = pCur->pNext;
			free(pCur);
			pCur = prev->pNext;
		}
		else
		{
			prev = pCur;
			pCur = pCur->pNext;
		}
	}
}

12、销毁单链表

这个特别注意特别注意特别注意!!!!!!!!!!!!!!

链表中每个结点都要free掉,不可以只free头结点,会造成内存泄漏

void SListDestroy(SListNode **ppFirst)
{
	SListNode *pDel,*pCur;
	pCur = *ppFirst;
	while (pCur!= NULL)
	{
		pDel = pCur->pNext;
		free(pCur);
		pCur = pDel;
	}
	*ppFirst = NULL;
	return;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值