程序员面试金典: 9.2链表 2.1移除未排序链表中重复的节点

#include <iostream>
#include <stdio.h>
#include <map>

using namespace std;
const int MAXSIZE = 10000;

/*
问题:编写代码,移除未排序链表中的重复节点
分析:删除重复节点,关键未排序,如果按照不排序做,那么第一遍需要统计所有元素及出现次数,
      第二遍扫描的时候,对于重复节点,没删除一次,计数器减1.
	  时间复杂度为O(N)
	  如果先对链表排序,时间复杂度为O(nlogN),没有必要
	  应该是先删前面每次碰到的,然后减少计数器次数

输入:
5(元素个数)
1 3 1 2 3
输出:
1 2 3

书上解法:在链表建立好后,遍历链表,如果当前元素没有再散列表中出现,
          则将当前元素加入散列表;否则,说明当前元素重复,删除该节点
		  时间复杂度为O(N),我使用的方法时间复杂度相同,但是优先删除前面
		  重复的元素,书上的解法优先删除后面重复的元素

关键:
1 判断当前节点的值是否在散列表出现,没有出现则加入散列表;否则删除当前节点
*/

typedef struct Node
{
	int value;
	Node* pNext;
}Node;

void deleteRepeatedNode(Node* pHead)
{
}

//构建连边,按照尾插法来做,返回节点值到出现次数的映射
map<int , int> buildList(int* pArray , Node* head , int num)
{
	map<int,int> valueToCount;
	if(pArray == NULL)
	{
		return valueToCount;
	}
	if(head == NULL)
	{
		return valueToCount;
	}


	//尾插法: 保留最后一个结尾节点,将新生成的节点插入在结尾节点,并令结尾节点为当前节点
	Node* pLast = head;
	//int num = sizeof(pArray) / sizeof(int);
	for(int i = 0 ; i < num ; i++)
	{
		int value = *(pArray + i);
		Node* pNode = new Node();
		pNode->value = value;
		pLast->pNext = pNode;
		pLast = pNode;

		//统计<结点值,出现次数的映射>
		map<int,int>::iterator it = valueToCount.find(value);
		//如果找到结点值,累加出现次数
		if(it != valueToCount.end() )
		{
			it->second += 1;
		}
		else
		{
			valueToCount.insert(pair<int,int>(value , 1));
		}
	}
	return valueToCount;
}

//删除重复节点
void deleteRepeatedNodes(map<int,int>& valueToCount , Node* pHead)
{
	if(pHead == NULL)
	{
		return;
	}
	if( valueToCount.empty() )
	{
		return;
	}
	Node* pNode = pHead->pNext;
	Node* pPrevious = pHead;

	//如果当前节点非空,开始统计
	while(pNode)
	{
		int value = pNode->value;
		map<int,int>::iterator it = valueToCount.find(value);
		//如果没找到,直接跳过
		if(it == valueToCount.end())
		{
			pPrevious = pNode;
			pNode = pNode->pNext;
			continue;
		}
		int count = it->second;

		//如果出现次数为1,无需删除,直接跳过
		if(count == 1)
		{
			pPrevious = pNode;
			pNode = pNode->pNext;
			continue;
		}

		//说明有重复节点,删除当前节点,这里设置之前的节点保留下来。删除节点的时候,要不要使得previous变更(不需要)
		if(count > 1)
		{
			Node* pDeleteNode = pNode;
			pNode = pNode->pNext;
			pPrevious->pNext = pNode;
			delete pDeleteNode;

			//更新出现次数
			valueToCount[value] = count - 1;
		}
	}
}

void printList(Node* pHead)
{
	if(NULL == pHead)
	{
		return;
	}
	Node* pNode = pHead->pNext;
	while(pNode)
	{
		cout << pNode->value << " ";
		pNode = pNode->pNext;
	}
	cout << endl;
}

void releaseList(Node* pHead)
{
	if(NULL == pHead)
	{
		return;
	}
	Node* pNode = pHead->pNext;
	Node* pPrevious = pHead;
	while(pNode)
	{
		Node* pDeleteNode = pNode;
		pPrevious->pNext = pNode->pNext;
		pNode = pNode->pNext;
		pPrevious = pPrevious->pNext;
		delete pDeleteNode;
	}
	//删除头结点
	delete pHead;
}

int main(int argc,char* argv[])
{
	int n;
	while(cin >> n)
	{
		int* pArr = new int[n];
		for(int i = 0 ; i < n ; i++)
		{
			cin >> pArr[i];
		}
		Node* pHead = new Node();
		map<int,int> valueToCount = buildList(pArr , pHead , n);
		deleteRepeatedNodes(valueToCount , pHead);
		printList(pHead);
		releaseList(pHead);
	}
	system("pause");
	return 0;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值