1. 程式人生 > >用歸併排序實現單鏈表的排序

用歸併排序實現單鏈表的排序

今天做了百度的一套資料探勘的筆試題,其中有一道對單鏈表進行歸併排序,因為剛學歸併排序的時候是針對陣列來說,所以這道題著實費了一點心思。

考點: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);
}