您的位置:首页 > 职场人生

合并两个排序好的链表/链表去重/链式快排

2013-10-01 02:39 489 查看
合并两个已经排好序的链表:

递归方式:如果其中一个链表为空,则直接返回第二个链表,如果第二个链表为空,则返回第一个链表。如果两个链表都不为空,则判断两个链表的表头大小,小值当作合并链表的头结点MergeHead,然后,后面的问题也是新的子问题,递归调用即可,具体可以看代码体会。

非递归方式:如果其中一个链表为空,则直接返回第二个链表,如果第二个链表为空,则返回第一个链表。如果两个链表都不为空,则判断两个链表的表头大小,小值当作合并链表的头结点MergeHead,同时需要另外三个指针指示位置,分别是MergeTail,head1,head2,往后迭代地比较head1和head2,MergeTail总是指向min(head1.key,head2.key),同时MergeHead与head1,head2是同步前移的,直至head1或者head2有一个为NULL,则MergeTail直接指向另一个链表的head即可。具体可以看代码体会。

#include<iostream>
using namespace std;
struct node
{
int key;
node* next;
node(int k):key(k),next(NULL){}
};
struct List
{
node* head;
List():head(NULL){}
};
node* ListInsert(node* head,node* z)
{
if(!head)
{
head=z;
return head;
}
else
{
head->next=ListInsert(head->next,z);
return head;
}
}
node* MergeList(node* head1,node* head2)
{
if(!head1)
return head2;
if(!head2)
return head1;

node* MergeHead=NULL;
node* MergeTail=NULL;
//head1 && head2都存在
if(head1->key < head2->key )
{
MergeHead = MergeTail = head1;
head1=head1->next;
}
else
{
MergeHead = MergeTail = head2;
head2=head2->next;
}

while(head1 && head2)
{
if(head1->key < head2->key)
{
MergeTail->next=head1;
MergeTail=head1;
head1=head1->next;
}
else
{
MergeTail->next=head2;
MergeTail=head2;
head2=head2->next;
}
}
if(head1)
MergeTail->next=head1;
else
MergeTail->next=head2;

return MergeHead;
}
node* recurMergeList(node* head1,node* head2)
{
if(!head1)//如果没有head1
return head2;
else if(!head2)//如果没有head2
return head1;
node* MergeHead=NULL;
if(head1->key < head2->key)
{
MergeHead=head1;
MergeHead->next=recurMergeList(head1->next,head2);
}
else
{
MergeHead=head2;
MergeHead->next=recurMergeList(head2->next,head1);
}
return MergeHead;
}

void main()
{
int A[]={1,3,4,5,9,11,16};
int B[]={2,6,12,13,15,17,19};
int len=sizeof(A)/sizeof(A[0]);
List* LA=new List;
for(int i=0;i<len;++i)
{
LA->head=ListInsert(LA->head,new node(A[i]));
}
List* LB=new List;
for(int i=0;i<len;++i)
{
LB->head=ListInsert(LB->head,new node(B[i]));
}
node* p=LA->head;
while(p)
{
cout<<p->key<<' ';
p=p->next;
}
cout<<endl;
p=LB->head;
while(p)
{
cout<<p->key<<' ';
p=p->next;
}
cout<<endl;
//p=recurMergeList(LA->head,LB->head);
p=MergeList(LA->head,LB->head);
while(p)
{
cout<<p->key<<' ';
p=p->next;
}
}


从一个未排序的链表中移除重复的项,增加一个条件:如果不允许使用临时的缓存,你如何解决这个问题?

思路:

1.如果可以使用额外空间,那就空间换时间,新建一个额外的数组保存之前出现过的项,下一次再出现同样的项,就删除一个.这种办法需要O(n)的空间和O(n)的时间.

2.如果不可以使用额外的空间,那可以考虑用蛮力法,用两个指针,每次扫描到一个结点,就用另一个指针扫描它后面的结点,删除重复项,时间效率是O(n^2).

3.如果可以先将链表排好序,那么删除重复结点的时间复杂度可以降到O(n),加上排序的复杂度,是O(nlgn+n).

以下是三种思路的实现:

思路1:

void RomoveRepeatNode1(node *head)
{
if(head==NULL)
return;
node *p=head, *q=head->next;

int hash[10000];
memset(hash,0,sizeof(hash));

hash[head->key] = true;

while(q)
{
if(hash[q->key])
{
p->next = q->next;
delete q;
q = p->next;

}
else
{
hash[q->key] = true;
p = q , q = q->next;
}
}
}

思路2:
void RomoveRepeatNode2(node *head)
{
if(head==NULL)
return;
node *p=head,*q=NULL,*prec=NULL; //prec指向q的前趋
while(p)
{
q=p->next,prec=p;
while(q)
{
if( p->key == q->key)
{
prec->next=q->next;
delete q;
q=prec->next;
}
else
{
prec=q,q=q->next;
}
}
p=p->next;
}
}

思路3:我们可以用改良版的链式快排对链表进行快速排序.然后,只需要比较相较相邻的结点value是否相同,则选择删除与否即可.

链式快排:(从线性快排稍做改进可以得到)

node* partition(node*  head,node* tail)
{
if( head==NULL ) return NULL;

int pivot=head->key;
node* p=head->next,*q=head;
while(p != tail)
{
if( p->key < pivot )
{
q=q->next;
swap(q->key,p->key);
}
p=p->next;
}
swap(head->key,q->key);
return q;
}
void QuickSort(node* l,node* r)
{
if( l != r)
{
node* pivot=partition(l,r);
QuickSort(l,pivot);
QuickSort(pivot->next,r);
}
}

void RomoveRepeatNode3(node *head)
{
QuickSort(head,NULL);
node* pDeleted=NULL;
while(head && head->next)
{
if( head->key == head->next->key )
{
pDeleted = head->next;
head->next = pDeleted->next;
delete pDeleted;
}
head=head->next;
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息