1. 程式人生 > >在O(1)時間刪除連結串列結點

在O(1)時間刪除連結串列結點

這道題題目可以描述為:給定單向連結串列的頭指標和一個結點指標,定義一個函式在O(1)時間刪除該結點。

本文中有關連結串列的結構體以及介面定義如下:

typedef   int DataType;

typedef struct ListNode{
	DataType data;
	struct  ListNode *next;
} ListNode;

//初始化

void  ListInit(ListNode **ppfirst)
{
	assert(ppfirst != NULL);
	*ppfirst = NULL;
}

這道題的思路可以理解為:如果要刪除結點i,先把i的下一個結點j的內容複製到i,然後把i的指標指向結點j的下一個結點,此時再刪除結點j,其效果剛好是把結點i刪除了。如下圖:
在這裡插入圖片描述


我們應該注意,對於尾結點,從頭結點開始遍歷找到為結點的前一個結點,然後完成刪除操作;如果連結串列中只有一個結點,即刪除頭結點,刪除之後把連結串列的頭結點置為NULL。

程式碼如下:

void DeleteNode(ListNode **phead, ListNode *pdelete)
{
	assert(phead && pdelete);

	//要刪除的不是尾結點
	if (pdelete->next != NULL)
	{
		ListNode *pnext = pdelete->next;
		pdelete->data = pnext->data;
		pdelete->next = pnext->next;
		free(pnext);
		pnext = NULL;
	}
	//刪除頭結點
	else if (*phead == pdelete)
	{
		free(pdelete);
		pdelete = NULL;
		*phead = NULL;
	}
	//刪除尾結點
	else
	{
		ListNode * pNode =* phead;
		while (pNode->next != pdelete)
		{
			pNode = pNode->next;
		}
		pNode->next = NULL;
        free(pdelete);
		pdelete = NULL;
	}
}

對於這種思路的複雜度可以解釋為對於n-1個非尾結點,可以在O(1)時把這個結點刪除;對於尾結點,由於要遍歷查詢,它的時間複雜度為O(n);因此總的平均時間複雜度為[(n-1)*O(1)+O(n)]/n,結果還是O(1),符合題目要求。