链表的归并排序

当我们需要对链表进行排序时,由于不能对它的元素进行随机访问,所以更适合使用归并排序,大名鼎鼎的快速排序用到链表上,效率也很低,原因还是在于不能对链表中的元素进行随机访问,同理,采用堆排序更是不可能的事情。

对单链表进行归并排序,单链表与数组相比只能顺序访问每个元素,因此在使用二路归并排序时关键在于找到链表的中间结点将链表一分为二:可以利用一个步长为2的指针和一个步长为1的指针同时遍历单链表,当步长为2的指针指向链表最后一个结点或者最后一个结点的下一个结点时,步长为1的指针即指向链表的中间结点。然后是两个有序单链表的合并问题。时间复杂度为O(N*logN),空间复杂度为O(1)。

//mergesort for LinkList

#include <iostream>

#include <cstdlib>

#include <time.h>

using namespace std;

typedef struct Node {

int data;

struct Node* next;

} LNode, *LinkList;

Node* getMiddle(LinkList L) {//无头结点链表

LNode *mid, *midl, *p;

midl = NULL, p = mid = L;

while (p != NULL && p->next != NULL) {//利用快慢指针找链表的中间位置并将链表1分为2

p = p->next->next;

midl = mid;

mid = mid->next;

}

midl->next = NULL;//将链表1分2

return mid;

}

void printList(LinkList L) {

LNode *p;

p = L;

while (p != NULL) {

cout << p->data << " ";

p = p->next;

}

cout << endl;;

}

void Merge(LinkList &La, LinkList Lb) {//将两个有序链表La和Lb合并成一个有序链表La,这里必须用引用LA,否则不能改变头指针,因为程序生成一个临时的LA,改变的只是临时生成的LA,而不是我们传入的LA

LNode *pa = La, *pb = Lb;

LinkList Lc = NULL;

LNode *q = NULL;

if (pa->data <= pb->data) {

Lc = q = pa;

pa = pa->next;

}

else {

Lc = q = pb;

pb = pb->next;

}

while (pa != NULL && pb != NULL) {

if (pa->data <= pb->data) {

q->next = pa, pa = pa->next, q = q->next;

}

else {

q->next = pb, pb = pb->next, q = q->next;

}

}

if (pa == NULL) q->next = pb;

else if (pb == NULL) q->next = pa;

La = Lc;//La重新指向合并后的链表

}

void MergeSort(LinkList &L) {//注意引用的使用

if (L == NULL || L->next == NULL) return;//当链表长度小于等于1时即不用再分

LinkList La, Lb;

Lb = getMiddle(L);

La = L;

MergeSort(La);

MergeSort(Lb);

Merge(La, Lb);

L = La;//返回的结果代回

}

void DestroyList(LinkList &L) {

LNode *p, *q;

p = q = L;

while (p != NULL) {

q = q->next;

free(p);

p = q;

}

}

int main() {

int len = 10, i;

LinkList L;

LNode *p;

if ((L = (LinkList)malloc(sizeof(LNode))) == NULL) {

cerr << "Error in allocate memory!" << endl;

return -1;

}

srand(time(NULL));

L->data = rand() mod 1000; L->next = NULL;

for (i = 1; i < len; i++) {

if ((p = (LNode*)malloc(sizeof(LNode))) == NULL) {

cerr << "Error in allocate memory!" << endl;

DestroyList(L);

return -1;

}

p->data = rand() mod 1000;

p->next = L->next;

L->next = p;//头插

}

cout << "The list before sorting:" << endl;

printList(L);

MergeSort(L);

cout << "\nThe list after sorting:" << endl;

printList(L);

DestroyList(L);

}

时间: 2024-11-05 11:34:58

链表的归并排序的相关文章

单链表的归并排序

#include<iostream> #include<time.h> using namespace std; //链表的归并排序 struct listnode{ int value; listnode* next; listnode(int value):value(value),next(NULL){} }; listnode* find_mid(listnode* head){ if(head==NULL)return NULL; listnode* fast=head;

leetcode23 多个拍好序的链表进行归并排序 (java版本)

题目: Merge k sorted linked lists and return it as one sorted list. Analyze and describe its complexity 思路1: 依次归并排序,首先归并前两个,然后归并完成的链表依次和剩下的链表进行归并排序 时间复杂度为O(m*n) 代码: public static ListNode mergeKLists1(ListNode[] lists){ int len = lists.length; if(len =

C++:探究纯虚析构函数以及实现数组的快速排序与链表的归并排序

C++:探究纯虚析构函数以及实现数组的快速排序与链表的归并排序 by 小威威 1.介绍 本篇博文将通过课后作业的(15 C++ Homework) D&A 5 Collection with Inheritance来讲解一些重要的排序与零散的知识.而且,本人以科学严谨的态度,对抽象类中析构函数的调用情况进行了分类讨论并一一试验,最终得出了"抽象类最好要定义纯虚析构函数"的结论,并不是凭空捏造,或者是从网上拷贝而来.但是,这仍然代表本人观点,不具有权威性,如有错误,欢迎大家批评指

链表的排序----链表的归并排序

链表的归并排序(LinkList merge sort) 首先来看看如果有两条已序(sorted)的链表 ListNode *A ,  和ListNode *B, 如何合并成一条已序的链表呢? ListNode * mergeTwoLists(ListNode *l1, ListNode *l2) { ListNode *head = new ListNode(-1); ListNode *p = head; for(;l1&&l2; p = p->next) { if(l1->

【LeetCode】 sort list 单链表的归并排序

题目:Sort a linked list in O(n log n) time using constant space complexity. 思路:要求时间复杂度O(nlogn) 知识点:归并排序,链表找到中点的方法 存在的缺点:边界条件多考虑!!! /** * LeetCode Sort List Sort a linked list in O(n log n) time using constant space complexity. * 题目:将一个单链表进行排序,时间复杂度要求为o

算法学习 - 链表之归并排序_O(1)空间_O(NlogN)时间_C++

归并排序 归并排序我在之前已经讲过了,并且给了在数组的数列的情况下的归并排序方法,而排序的时间复杂度为O(NlogN).想看的话链接如下: 归并排序,快排,冒泡排序 但是这个归并排序有一个缺点:需要O(n)的额外空间. 那么这个缺点在什么情况下会解决呢?就是数列是以链表形式存储的时候!就不需要额外的申请O(n)级别的空间. 那么我们为什么要用归并排序呢? 不是还有快排,堆排么?都是速度很快的排序.其实在链表中是不适合的!因为在快排的时候,查找标杆是O(1)级别的,但是在链表中只能得到head节点

归并排序 求逆序数 链表的归并排序 多线程归并排序 java

import java.util.Scanner; public class Main { private static int count=0; public static void mergesort(int a[],int low,int high) { if(low<high) { int mid=(low+high)>>1; mergesort(a,low,mid); mergesort(a,mid+1,high); merge(a,low,mid,high); } } pri

单链表排序--归并排序

#include <iostream> #include <cstdlib> using namespace std; struct ListNode //默认为public { int data; ListNode* next; ListNode(int x, ListNode* nextNode):data(x), next(nextNode){} }; ListNode* mergeData(ListNode* first, ListNode* second) { if(fi

单向链表的归并排序(Java)

Sort a linked list in O(n log n) time using constant space complexity. 1 package SortList; 2 3 import java.util.Iterator; 4 5 class ListNode { 6 7 int val; 8 ListNode next; 9 ListNode(int val) { 10 this.val = val; 11 } 12 } 13 14 public class Solutio