单链表的学习

链表是一种很重要的数据结构,它由两部分组成,第一个部分是咱们要储存的数据,第二个部分是指向下一个储存单元的指针。链表在使用中有顺序表没法比拟的灵活性,免去了储存空间不够,又有可能浪费的尴尬。数据结构


单链表有一个头指针pHead,当咱们没有数据要储存的时候它指向NULL,当咱们有数据的时候它指向第一块储存单元。储存单元里面有两个部分,前面的部分是咱们要储存的数据data,后面的部分是指向下一个储存单元的指针pNext,当后面没有储存单元的时候就指向NULL。那么咱们储存的数据在内存中并非连续储存的,而是在内存中跳跃式储存的。要使用的时候再直接申请一块空间。
ide


下面是链表的定义
函数

typedef struct ListNode
{
	DataType data;
	struct ListNode *pNext;
}SListNode, *PSListNode;

能够看到单链表的两个成员。为了使用方便咱们直接typedef重命名。指针


单链表有几种基本操做,好比插入数据,删除数据,那我下面实现了一下。内存


首先,我写了一个申请新单元的函数
it

PSListNode ByeNode(DataType data)
{
	PSListNode pNewNode = (PSListNode)malloc(sizeof(SListNode));
	if (NULL != pNewNode)
	{
		pNewNode->data = data;
		pNewNode->pNext = NULL;
	}
	return pNewNode;
}

它能够为咱们直接在内存中申请一块新的空间而且返回它的地址。class


第一个实现就是咱们从尾部插入数据
变量

void PushBack(PSListNode* pHead, DataType data)
{
	PSListNode pNode = NULL;
	PSListNode pNewNode = NULL;

	assert(pHead);

	if (NULL == *pHead)
	{
		*pHead = ByeNode(data);
	}
	else
	{
		pNode = *pHead;
		while (NULL != pNode->pNext)
		{
			pNode = pNode->pNext;
		}
		pNewNode = ByeNode(data);
		pNode->pNext = pNewNode;
	}
}

这里咱们传的参数是二级指针,由于咱们是要改变它指针的指向。假如咱们直接传递一级指针,那么咱们并不能改变它的指向,至关于咱们函数中操做了半天,其实都是在操做一个临时的指针变量,只不过他跟咱们的头指针的指向是同样的,最后什么也没有返回,头指针什么变化都没有。List


接下来就是咱们从尾部删除数据的实现链表

void PopBack(PSListNode* pHead)
{
	/*PSListNode pPerNode = NULL;
	PSListNode pCurNode = NULL;
	assert(pHead);

	if (NULL == *pHead)
	{
		return;
	}
	else
	{
		pCurNode = *pHead;
		pPerNode = pCurNode;

		while (NULL != pCurNode->pNext)
		{
			pPerNode = pCurNode;
			pCurNode = pCurNode->pNext;
		}
		if (pCurNode==pPerNode)
		{
			*pHead = NULL;
			free(pCurNode);
			pCurNode = NULL;
			pPerNode = NULL;
		}
		else
		{
			pPerNode->pNext = NULL;
			free(pCurNode);
			pCurNode = NULL;
		}	
	}*/

	PSListNode pPerNOde = *pHead;
	PSListNode pCurNode = *pHead;
	assert(pHead);

	if (NULL == *pHead)
	{
		return;
	}
	else
	{
		if (NULL == pCurNode->pNext)
		{
			return;
		}
		else
		{
			while (NULL!=pCurNode->pNext)
			{
				pPerNOde = pCurNode;
				pCurNode = pCurNode->pNext;
			}

			pPerNOde->pNext = NULL;
			free(pCurNode);
			pCurNode = NULL;
		}
	}

}

注释中的代码是我刚开始的时候写的,我发现他的逻辑不是很清晰,在第二个部分中我把链表中只有一个节点的状况单列了出来,逻辑比以前清晰了不少。


那咱们也能够在链表的头部插入数据

void PushFront(PSListNode* pHead, DataType data)
{
	PSListNode NewNode = NULL;
	assert(pHead);

	if (NULL == *pHead)
	{
		*pHead = ByeNode(data);
	}
	else
	{
		NewNode = ByeNode(data);
		if (NULL == NewNode)
		{
			return;
		}
		else
		{
			NewNode->pNext = (*pHead);
			*pHead = NewNode;
		}
	}
}

思路有了以前的两个函数作铺垫想起来并不难。申请一块新的空间以后,让它的pNext指向咱们以前的第一块空间。而后改变咱们的头指针的指向,让它指向咱们的新空间。这里注意咱们申请空间是有可能失败的,因此要判断一下。


固然还有从头部删除

void PopFront(PSListNode* pHead)
{
	assert(pHead);

	if (NULL == *pHead)
	{
		return;
	}
	else
	{
		PSListNode pCurNode = *pHead;

		pCurNode = pCurNode->pNext;
		free(*pHead);
		*pHead = pCurNode;
		pCurNode = NULL;
	}
}

千万不要忘记free空间以后要给指针赋空,不然会造成野指针。


还有就是寻找咱们链表中的元素

PSListNode Find(PSListNode pHead, DataType data)
{
	if (NULL == pHead)
	{
		return NULL;
	}
	else
	{
		PSListNode pNode = pHead;
		/*while (data != pNode->data)
		{
			if (NULL == pNode->pNext)
			{
				return NULL;
			}
			pNode = pNode->pNext;
		}
		return pNode;*/

		while (NULL != pNode)
		{
			if (data == pNode->data)
				return pNode;

			pNode = pNode->pNext;
		}
		return NULL;
	}
}

注释掉的代码是我第一次写的,后来我发现它的逻辑有点问题,我能够更简单的实现它的功能。

最后返回我要找的数据的位置,假如没有找到那么就返回空。


打印我链表中的元素

void PrintList(PSListNode pHead)
{
	PSListNode pNode = pHead;

	while (NULL!=pNode)
	{
		printf("%d ", pNode->data);
		pNode = pNode->pNext;
	}

	printf("\n");
}


删除个人任意位置的节点

void  Erase(PSListNode* pHead, PSListNode pos)
{
	PSListNode pCurNode = pos;
	PSListNode pPerNode = NULL;
	assert(pHead);

	if (NULL == *pHead)
	{
		return;
	}
	else
	{
		pPerNode = *pHead;
		while (pPerNode->pNext != pCurNode)
		{
			pPerNode = pPerNode->pNext;
		}
		pPerNode->pNext = pCurNode->pNext;
		free(pCurNode);
		pCurNode = NULL;
	}
}


在个人链表的任意位置插入一个节点

void  Insert(PSListNode* pHead, PSListNode pos, DataType data)
{
	PSListNode ptmpNode = *pHead;
	PSListNode pNode = *pHead;
	assert(pHead);

	if (NULL == *pHead)
	{
		*pHead = ByeNode(data);
	}
	else
	{
		while (pos != pNode)
		{
			if (NULL == pNode)
			{
				return;
			}
			pNode = pNode->pNext;
		}
		ptmpNode = pNode->pNext;
		pNode->pNext = ByeNode(data);
		pNode = pNode->pNext;
		pNode->pNext = ptmpNode;
	}
}
相关文章
相关标签/搜索