今天做了百度的一套数据挖掘的笔试题,其中有一道对单链表进行归并排序,因为刚学归并排序的时候是针对数组来说,所以这道题着实费了一点心思。
考点:1归并算法;2单双步求中点;3链表指针的操作,以及边界空指针问题;4内存分配与回收;
单链表与数组相比只能顺序访问每个元素,因此在使用二路归并排序时关键在于找到链表的中间结点将链表一分为二:可以利用快慢指针同时遍历单链表,当步长为2的指针指向链表最后一个结点或者最后一个结点的下一个结点时,步长为1的指针即指向链表的中间结点。然后是两个有序单链表的合并问题。时间复杂度为O(N*logN),空间复杂度为O(1)。注意空间复杂度,此时是单链表的一个优势,直接通过更改链表指针完成排序,而不需另外分配空间,这就是考察了人的思维了。不说多的,非常感谢网上一些老师的答案和分析,让我学会了很多知识点,谢谢啦~
// ListNodeMerge_sort.cpp : 定义控制台应用程序的入口点。
//
#include "stdafx.h"
#include<cstdlib>
#include <iostream>
#include <time.h>
using namespace std;
struct Node
{
int v;
struct Node* next;
};
/*分割一个链表为两部分,通过指针返回结果,使用单双步指针*/
void FrontBackSplit(Node *source,Node** front,Node** back)
{
Node *slow=NULL, *fast=NULL;
if (source == NULL || source->next == NULL)
{
/*length<2*/
*front = source;
*back = NULL;
}
else
{
slow = source;
fast = source->next;
}
while (fast != NULL&&fast->next != NULL)
{
fast = fast->next;
if (fast != NULL)
{
slow = slow->next;
fast = fast->next;
}
}
/*slow在中间位置的前面*/
*front = source;
*back = slow->next;
slow->next=NULL; //完成一分为二;
}
Node* Merge(Node *source1, Node *source2)
{
Node *temp=NULL ;
if (source1 == NULL)
return (source2);
else if (source2 == NULL)
return (source1);
if (source1->v <= source2->v)
{
temp = source1;
temp->next = Merge(source1->next, source2);
}
else
{
temp = source2;
temp->next = Merge(source1, source2->next);
}
return temp;
}
void mergesort(Node **L)
{
Node *P = *L;
if (P == NULL || P->next == NULL) return;
Node *Pa, *Pb;
FrontBackSplit(P,&Pa,&Pb);
mergesort(&Pa);
mergesort(&Pb);
*L=Merge(Pa, Pb);
}
Node *merge_sort(Node* L)
{
mergesort(&L);
return NULL;
}
void printList( Node * Node)
{
while (Node != NULL)
{
printf("%d ", Node->v);
Node = Node->next;
}
}
void DestroyList(Node *L)
{
Node *p, *q;
p = q = L;
while (p != NULL) {
q = q->next;
free(p);
p = q;
}
}
int _tmain(int argc, _TCHAR* argv[])
{
int len = 10, i;
Node *L;
Node *p;
if ((L = (Node*)malloc(sizeof(Node))) == NULL) {
cerr << "Error in allocate memory!" << endl;
return -1;
}
srand(time(NULL));
L->v = rand() % 1000;
L->next = NULL;
for (i = 1; i < len; i++)
{
if ((p = (Node*)malloc(sizeof(Node))) == NULL)
{
cerr << "Error in allocate memory!" << endl;
DestroyList(L);
return -1;
}
p->v = rand() % 1000;
p->next = L->next;
L->next = p;
}
cout << "The list before sorting:" << endl;
printList(L);
merge_sort(L);
cout << "\nThe list after sorting:" << endl;
printList(L);
DestroyList(L);
}