1. 程式人生 > >n個有序單鏈表合併

n個有序單鏈表合併

          n個長度為m的有序單鏈表進行合併,使合併之後的單鏈表保持有序,求時間複雜度。這是今年阿里巴巴武漢實習生招聘的一道填空題,我參加了並最終獲得offer只可惜由於事先簽了騰訊所以本著誠信的原則,我選擇放棄阿里相對豐厚的實習生薪水。感覺這是一道很開放的題目,也就是一共有n*m個元素,所以該問題時間複雜度的下限為O(n*m)。下面談談我的想法(以從小到大為準)。

1.暴力法

       拿到此題,第一想法就是每次挑選最小的,由於有序,故最小元素只可能是所有單鏈表第一個元素中的最小者,一次挑選時間複雜度為O(n),總共要處理n*m次,所以總的時間複雜度為O(n*m*m),空間複雜度為O(1)。

2.最小堆

      從n個元素中找最小的,可以嘗試建立含n個元素的最小堆,每次取最小堆中的根節點元素,然後將該節點所在單鏈表中的下一個元素補上,調整堆維持最小堆的性質,此過程時間複雜度為O(log(n)),總共要處理n*m次,所以總的時間複雜度O(n*m*log(n)),此時必須記錄最小堆對應的拓撲結構,故需額外開闢空間,空間複雜度為O(n)。程式碼相簡單,就不貼上了。

3.歸併排序

     原問題可以和歸併排序類比,進而可以看作是已經在歸併排序對應的狀態樹上自底向上進行了log(m)次的,得到n個長度為m的有序單鏈表,接著只需繼續歸併排序的過程即可,還需進行log(n),而每次即對應每一層有n.m的元素,時間複雜度為O(n*m*log(n))無需額外空間,故空間複雜度為O(1)。貼段程式碼:

#include<iostream>
#include<ctime>
using namespace std;

struct SNode
{
	int key;
	SNode *next;
};

class SList
{
private :
	SNode *head;
public:
	SList();
	void insertSort(int);
	void insertSort(SList &);
	void merge(SList &);
	void print();
};

SList::SList()
{
	head=new SNode;
	head->next=NULL;
}

void SList::insertSort(int tmpKey)
{
	SNode *p=new SNode;
	p->key=tmpKey;
	p->next=NULL;
	SNode *pre=NULL,*cur=head->next;
	while(cur!=NULL)
	{
		if(cur->key>=tmpKey)
		break;
		pre=cur;
		cur=cur->next;
	}
	if(NULL==pre)
	{
		p->next=head->next;
		head->next=p;
	}
	else 
	{
		pre->next=p;
		p->next=cur;
	}
}

void SList::merge(SList &tempSList)
{
	SNode *p,*q,*com;
	com=head;
	p=head->next;
	q=tempSList.head->next;
	while(p!=NULL&&q!=NULL)
	{
		if(p->key<q->key)
		{
			com->next=p;
			p=p->next;
		}
		else
		{
			com->next=q;
			q=q->next;
		}
		com=com->next;
	}
	if(q!=NULL)
		com->next=q;
	if(p!=NULL)
		com->next=p;
}

void SList::print()
{
	SNode *p=head->next;
	while(p!=NULL)
	{
		cout<<p->key<<"  ";
		p=p->next;
	}
	cout<<endl;
}

int mergeSort(SList tArray[],int tLeft,int tRight)
{
	if(tLeft==tRight)
		return tLeft;
	int mid=(tLeft+tRight)>>1;
	int l=mergeSort(tArray,tLeft,mid);
	int r=mergeSort(tArray,mid+1,tRight);
	tArray[l].merge(tArray[r]);
	return l;
}

int main()
{
	int n=10,i,j=0;
	SList *mySList=new SList[n];
	while(j<n)
	{
		i=0;
	 while(i++<n)
	 {
		mySList[j].insertSort(rand()%100);
	 }
	  mySList[j].print();
	  j++;
	}
	mergeSort(mySList,0,9);
	mySList[0].print();
	system("pause");
	return 0;
}

4.雜湊雜湊法

     如果元素方便雜湊雜湊,那麼總的時間複雜度可以有效降到O(n*m),不過空間複雜度會達到O(n*m)。此題元素型別沒說,所以感覺這樣不妥,但也是一種可以想象的解題方向。