利用优先级队列解决k路归并问题

问题:

把k个有序表合并成一个有序表。k个有序表总共有n个元素。


解决思路(书上的):

把每个表的的当前元素放入优先级队列中,每次从优先级队列中删除最小值并放入到新表中,然后加入入此序列的下一个元素。

时间复杂度分析:每次操作需要logk时间,因此总共需要nlogk的时间。


实现代码:

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<vector>

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

#define K 50				//K路合并的最大K


/*--------------------------------------------------------------------------
	优先级队列的实现
  --------------------------------------------------------------------------*/
#define INIFINE -10000
#define LEFT(i) (2*(i))   
#define RIGHT(i) (2*(i)+1)
#define PARENT(i) ((i)/2)

class PriorityQueue
{
	public:
		PriorityQueue() ;
		PriorityQueue( int *pFirst, int *pLast ) ;

		~PriorityQueue() ;

	public:
		void BuildMinHeap() ;
		void MinHeapInsert(int nKey)  ;
		int HeapMinimun() ;
		int HeapExtractMin() ;

		void DebugPrint() ;


	private:
		void MinHeapify( int i ) ;
		void HeapDecreaseKey(int i,int nKey) ;


	private:
		enum QUE_SIZE { MAX = 1000 } ;   //The heap max size

	private :
		int m_nHeapSize ;
		int m_nLength ;
		int m_C[MAX];

} ;


void PriorityQueue::DebugPrint()
{
	for(int i = 1 ; i <= m_nHeapSize ; ++i)
	{
		cout << m_C[i] << ' ' ;
	}
	cout << endl ;
}


PriorityQueue::~PriorityQueue()
{
	m_nHeapSize = 0 ;
	m_nLength = 0 ;
}


PriorityQueue::PriorityQueue( int *pFirst, int *pLast )
{
	int i = 1 ;
	m_nHeapSize = m_nLength = 0 ;

	while(pFirst != pLast)
	{
		m_C[i] = *pFirst ;
		pFirst++ ;
		m_nLength++ ;
		i++ ;
	}
	m_nHeapSize = m_nLength ;
	BuildMinHeap() ;
}


PriorityQueue::PriorityQueue():
	m_nHeapSize(0) ,m_nLength(0)
{
}



int PriorityQueue::HeapExtractMin()
{
	int nMin = 0 ;
	if(m_nHeapSize < 1)
	{
		return -1 ;
	}
	nMin = m_C[1] ;
	m_C[1] = m_C[m_nHeapSize] ;
	m_nHeapSize-- ;
	m_nLength-- ;
	MinHeapify(1) ;

	return nMin ;
}

int PriorityQueue::HeapMinimun( )
{
	return m_C[1] ;
}

void PriorityQueue::BuildMinHeap()
{
	int i ;
	m_nHeapSize = m_nLength ;

	for(i = m_nLength/2 ; i >= 1 ; --i)
	{
		MinHeapify(i) ;
	}
}

void PriorityQueue::MinHeapify( int i )
{
	int l,r,nTemp,nMininum ;
	l = LEFT(i) ;
	r = RIGHT(i) ;

	if(l <= m_nHeapSize && m_C[i] > m_C[l])
	{
		nMininum = l ;
	}
	else
	{
		nMininum = i ;
	}

	if(r <= m_nHeapSize && m_C[nMininum] > m_C[r] )
	{
		nMininum = r ;
	}

	if(i != nMininum )
	{
		nTemp = m_C[i] ;
		m_C[i] = m_C[nMininum] ;
		m_C[nMininum] = nTemp ;
		MinHeapify(nMininum) ;
	}
}



void PriorityQueue::MinHeapInsert(int nKey)
{
	m_nHeapSize++ ;
	m_nLength++ ;
	m_C[m_nHeapSize] = -INIFINE ; //aim to keep the heap attribute
	HeapDecreaseKey( m_nHeapSize,nKey ) ;

}

void PriorityQueue::HeapDecreaseKey(int i,int nKey)
{
	int nTemp = 0 ;
	if(nKey > m_C[i])
	{
		return ;
	}

	m_C[i] = nKey ;

	while(i > 1 && m_C[PARENT(i)] > m_C[i])
	{
		nTemp = m_C[i] ;
		m_C[i] = m_C[PARENT(i)] ;
		m_C[PARENT(i)] = nTemp ;
		i = PARENT(i) ;
	}
}

/*--------------------------------------------------------------------------
	优先级队列的实现
  --------------------------------------------------------------------------*/


typedef struct ListNode
{
	int m_Data ;
	ListNode *m_pNext ;
} ListNode ;


int FindNextNodeToHeap( ListNode* A[] ,int k ,int nKey )  ;
void PrintResult(int C[], int nLen ) ;


void PrintResult(int C[],int nLen) 
{
	for(int i = 0 ; i < nLen ; ++i )
	{
		cout << C[i] << ' ' ;
	}
	cout << endl ;
}

int FindNextNodeToHeap( ListNode* A[] ,int k ,int nKey)  
{
	int i = 0 ;
	for(i = 0 ; i < k ; ++i)
	{
		if(A[i]->m_pNext != NULL && A[i]->m_pNext->m_Data == nKey )
		{
			return i ;
		}
	}
	return -1 ;
}


int main(void)
{
	int i,j,k,n,nTotalSize ;  //k为有多少路序列,
	ListNode* A[K] ;

	freopen("in.txt","r",stdin) ;  //测试文件

	while(scanf("%d",&k) != EOF )
	{
		nTotalSize = 0 ; 
		for(i = 0 ; i < k ; ++i)
		{
			ListNode *pNode = new ListNode ;
			pNode->m_pNext = NULL ;
			pNode->m_Data = 0 ;
			A[i] = pNode ;

			ListNode *pCurNode = pNode ;

			scanf("%d",&n) ;

			for(j = 0 ; j < n ; ++j)
			{
				ListNode *pNode = new ListNode ;	
				pNode->m_pNext = NULL ;
				scanf("%d",&(pNode->m_Data)) ;	

				pCurNode->m_pNext = pNode ;
				pCurNode = pNode ;

				nTotalSize++ ;
			}
		}

		PriorityQueue queue ;

		int *pC = new int[nTotalSize] ;
		int nNextNodeToHeap = -1 ;  
		int l = 0 ;

		for(i = 0 ; i < k ; ++i)
		{
			queue.MinHeapInsert( A[i]->m_pNext->m_Data ) ;
		}
		
		while( nTotalSize-- > 0 )
		{
			pC[l] = queue.HeapExtractMin() ;


			nNextNodeToHeap = FindNextNodeToHeap( A,k,pC[l]) ;
			ListNode *pToDelNode = A[nNextNodeToHeap]->m_pNext ;
			A[nNextNodeToHeap]->m_pNext = A[nNextNodeToHeap]->m_pNext->m_pNext ;

			delete  pToDelNode ;

			if( A[nNextNodeToHeap]->m_pNext != NULL)
			{
				queue.MinHeapInsert( A[nNextNodeToHeap]->m_pNext->m_Data ) ;
			}

			l++ ;
		}

		PrintResult(pC,l) ;

		delete [] pC ;

	}
	
	return 0 ;
}

/*
测试用例:
Input Sample
5				//有多少路,5路
3				//第一路有多少个元素
4 5 8			//第一路的输入元素
5			    //第二路有多少个元素
1  3 7 9 10		//第二路的输入元素
2				//第三路有多少个元素
2 4				//第三路的输入元素
4				//第四路有多少个元素
5 6 7			//第四路的输入元素
1				//第五路有多少个元素
1				//第五路的输入元素

Output Sample
1 1 2 3 4 4 5 5 6 7 7 8 9 10 11

*/



题外话:

好久没写博客了,当然,偷懒是主要原因啦~~

另外工作也落实了,很开心,大学的努力有回报了~~

不过,这也只是一个新的起点而已,日子还是得继续~~







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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值