單鏈表的學習

鏈表是一種很重要的數據結構,它由兩部分組成,第一個部分是咱們要儲存的數據,第二個部分是指向下一個儲存單元的指針。鏈表在使用中有順序表沒法比擬的靈活性,免去了儲存空間不夠,又有可能浪費的尷尬。數據結構


單鏈表有一個頭指針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;
	}
}
相關文章
相關標籤/搜索