剑指Offer----面试题13:在O(1)时间删除链表结点

题目:

给定单向链表的头结点和一个指针结点,定义一个函数在O(1)时间删除该结点。


方法一:

在以往的算法中,我们往往都是从链表的头结点开始循环遍历找到该结点的前一个结点a,通过调整该结点a的指针来删除结点,然而这种算法的时间复杂度为O(n),如下如所示:



我们也可以找到该结点i的下一个结点j,将j的内容复制到需要删除的结点i上来覆盖掉其原有的内容,然后再把下一个结点j删掉就可以了!如下图所示:


源代码:

List.h

#ifndef LIST_NODE_H
#define LIST_NODE_H

namespace ListSpace2
{

	struct ListNode
	{
		int element;
		ListNode *next;
	};

	ListNode * CreateListNode(int valude);
	void ConnectListNodes(ListNode *pCurrent, ListNode *pNext);
	void printListNode(ListNode *pHead);
	void printList(ListNode *pHead);
	void printReversingly_Iteratively(ListNode *pHead);
	void printReversingly_Recursively(ListNode *pHead);
	void DestoryList(ListNode **pHead);
	void AddToTail(ListNode ** pHead, int value);
	void RemoveNode(ListNode ** pHead, int value);

}

#endif

List.cpp
#include"List.h"
#include<iostream>
#include<stack>

namespace ListSpace2
{
	ListNode * CreateListNode(int value)
	{
		ListNode *pNew = new ListNode();
		pNew->element = value;
		pNew->next = NULL;

		return pNew;
	}

	void ConnectListNodes(ListNode *pCurrent, ListNode *pNext)
	{
		if (pCurrent == NULL)
			std::cout << "Linking Error..." << std::endl;
		else
		{
			pCurrent->next = pNext;
		}
	}

	void printListNode(ListNode *pHead)
	{
		if (pHead == NULL)
			std::cout << "The value of this node is empty" << std::endl;
		else
			std::cout << "The value of this node is " << pHead->element << std::endl;
	}

	void printList(ListNode *pHead)
	{
		if (pHead == NULL)
			std::cout << "The list is empty" << std::endl;
		else
		{
			ListNode *pNew = pHead;
			while (pNew != NULL)
			{
				std::cout << pNew->element << "  ";
				pNew = pNew->next;
			}
		}
	}

	void printReversingly_Iteratively(ListNode *pHead)
	{

		if (pHead == NULL)
		{
			std::cout << "The list is empty" << std::endl;
			return;
		}
		else
		{
			std::stack<ListNode *> st;
			ListNode * pNew = pHead;
			while (pNew != NULL)
			{
				st.push(pNew);
				pNew = pNew->next;
			}

			while (!st.empty())
			{
				std::cout << st.top()->element << "  ";
				st.pop();
			}
		}
	}

	void printReversingly_Recursively(ListNode *pHead)
	{
		if (pHead != NULL)
		{
			if (pHead->next != NULL)
				printReversingly_Recursively(pHead->next);
			std::cout << pHead->element << "  ";
		}
	}

	void DestoryList(ListNode **pHead)
	{
		ListNode *pNew = *pHead;
		while (pNew != NULL)
		{
			*pHead = (*pHead)->next;
			delete pNew;
			pNew = *pHead;
		}
	}

	void AddToTail(ListNode ** pHead, int value)
	{
		ListNode *pNew = new ListNode();
		pNew->element = value;
		pNew->next = NULL;

		if (*pHead == NULL)
			*pHead = pNew;
		else
		{
			//找到最后一个结点
			ListNode *node = *pHead;
			while (node->next != NULL)
				node = node->next;

			node->next = pNew;
		}
	}

	void RemoveNode(ListNode ** pHead, int value)
	{
		if (pHead == NULL || *pHead == NULL)
			return;

		ListNode *pToBeDeleted = NULL;
		if ((*pHead)->element == value)
		{
			pToBeDeleted = *pHead;
			*pHead = (*pHead)->next;
		}
		else
		{
			ListNode *node = *pHead;
			while (node->next != NULL && node->next->element != value)
				node = node->next;
			if (node->next != NULL && node->next->element == value)
			{
				pToBeDeleted = node->next;
				node->next = node->next->next;
			}
		}

		if (pToBeDeleted != NULL)
		{
			delete pToBeDeleted;
			pToBeDeleted = NULL;
		}
	}
}

主函数

#include"List.h"
#include<iostream>

using std::cout;
using std::endl;

using namespace ListSpace2;

void DeleteNode(ListNode **pHead, ListNode *pToBeDeleted)
{
	if (pHead == NULL || pToBeDeleted == NULL)
	{//结点为空,删除失败!
		cout << "删除结点失败!" << endl;
		return;
	}

	//怎么判断被删除的结点是否为单向链表的结点呢?
	//因为如果该结点不是链表中的结点,那么删除该结点是没有意义的!

	//链表中有多个结点,且被删除的结点不是尾结点
	if (pToBeDeleted->next != NULL)
	{
		ListNode *temp = pToBeDeleted->next;
		pToBeDeleted->element = pToBeDeleted->next->element;
		pToBeDeleted->next = pToBeDeleted->next->next;
		
		delete temp;
		temp = NULL;
	}
	//链表中只有一个结点,删除头结点
	else if (*pHead == pToBeDeleted)
	{
		delete *pHead;
		*pHead = NULL;
		pToBeDeleted = NULL;
	}
	//链表中有多个结点,删除最后一个结点
	else
	{
		ListNode *temp = *pHead;

		while (temp->next != pToBeDeleted)
			temp = temp->next;

		temp->next = NULL;
		delete pToBeDeleted;
		pToBeDeleted = NULL;
	}
}

//删除多结点链表中非尾结点的链表
void test1()
{
	cout << "===========删除多结点链表中非尾结点的链表=============" << endl;
	ListNode *list1 = CreateListNode(1);
	ListNode *list2 = CreateListNode(2);
	ListNode *list3 = CreateListNode(3);
	ListNode *list4 = CreateListNode(4);
	ListNode *list5 = CreateListNode(5);
	ListNode *list6 = CreateListNode(6);

	ConnectListNodes(list1, list2);
	ConnectListNodes(list2, list3);
	ConnectListNodes(list3, list4);
	ConnectListNodes(list4, list5);
	ConnectListNodes(list5, list6);

	printList(list1);
	cout << endl;
	DeleteNode(&list1, list3);
	printList(list1);
	cout << endl;
}

//删除多结点链表中尾结点的链表
void test2()
{
	cout << "===========删除多结点链表中尾结点的链表=============" << endl;
	ListNode *list1 = CreateListNode(1);
	ListNode *list2 = CreateListNode(2);
	ListNode *list3 = CreateListNode(3);
	ListNode *list4 = CreateListNode(4);
	ListNode *list5 = CreateListNode(5);
	ListNode *list6 = CreateListNode(6);

	ConnectListNodes(list1, list2);
	ConnectListNodes(list2, list3);
	ConnectListNodes(list3, list4);
	ConnectListNodes(list4, list5);
	ConnectListNodes(list5, list6);

	printList(list1);
	cout << endl;
	DeleteNode(&list1, list6);
	printList(list1);
	cout << endl;
}

void test3()
{
	cout << "===========删除单结点链表中头结点的链表=============" << endl;
	ListNode *list1 = CreateListNode(1);
	printList(list1);
	cout << endl;
	DeleteNode(&list1, list1);
	printList(list1);
	cout << endl;
}

void test4()
{
	cout << "===========删除空链表中空结点的链表=============" << endl;
	DeleteNode(NULL, NULL);
}

int main()
{
	test1();
	test2();
	test3();
	test4();

	system("pause");
	return 0;
}



运行结果:
===========删除多结点链表中非尾结点的链表=============
1  2  3  4  5  6
1  2  4  5  6
===========删除多结点链表中尾结点的链表=============
1  2  3  4  5  6
1  2  3  4  5
===========删除单结点链表中头结点的链表=============
1
The list is empty

===========删除空链表中空结点的链表=============
删除结点失败!
请按任意键继续. . .

分析:对于n-1个非尾结点而言,时间复杂度为O(1),对于尾结点而言,时间复杂度为O(n),总的时间复杂度为((n-1)*O(1) + O(n))/n,其结果还是O(1)。

注意:题目中没有判断被删除的结点是否为链表中的结点!



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值