对链表进行归并排序
2013-08-23 17:20
281 查看
对链表进行归并排序
当我们需要对链表进行排序时,由于不能对它的元素进行随机访问,所以更适合使用归并排序,大名鼎鼎的快速排序用到链表上,效率也很低,原因还是在于不能对链表中的元素进行随机访问,同理,采用堆排序更是不可能的事情。
算法具体实现时需要一个指向头节点(链表的第一个节点,链表中不包含额外的一个节点来作头节点)的指针,这是因为在算法实现的时候,不大可能第一个节点正好就是所有元素中最小的一个,则链表的头节点会改变,因此我们需要一个指向头节点的指针来存储不断变化的头节点。
算法思想:
MergeSort(headRef)
#include <stdio.h>
#include <stdlib.h>
/*Link list node*/
struct node
{
int data;
struct node* next;
};
/*function prototype */
struct node* SortedMerge(struct node* a, struct node* b);
void FrontBackSplit(struct node* source, struct node** frontRef, struct node** backRef);
/*sorts the linked list by changing next pointers(not data) */
void MergeSort(struct node** headRef)
{
struct node* head = *headRef;
struct node* a;
struct node* b;
/*base case-- length 0 or 1 */
if((head == NULL) || (head->next == NULL))
{
return;
}
/*Split head into 'a' and 'b' sublists */
FrontBackSplit(head, &a, &b);
/*Recursively sort the sublists */
MergeSort(&a);
MergeSort(&b);
/* answer = merge the two sorted lists together */
*headRef = SortedMerge(a, b);
}
struct node* SortedMerge(struct node* a, struct node* b)
{
struct node* result = NULL;
/* Base cases */
if(a == NULL)
return (b);
else if(b == NULL)
return (a);
/* Pick either a or b recur */
if(a->data <= b->data)
{
result = a;
result->next = SortedMerge(a->next, b);
}
else
{
result = b;
result->next = SortedMerge(a, b->next);
}
return (result);
}
/* UTILITY FUNCTIONS */
/* Split the nodes of the given list into front and back halves,
and return the two lists using the references parameters.
If the length is odd, the extra node shold go in the front list.
Uses the fast/slow pointer strategy. */
void FrontBackSplit(struct node* source, struct node** frontRef, struct node** backRef)
{
struct node* fast;
struct node* slow;
if(source == NULL || source->next == NULL)
{
*frontRef = source;
*backRef = NULL;
}
else
{
slow = source;
fast = source->next;
/* Advance 'fast' two nodes, and advance 'slow' one node */
while(fast != NULL)
{
fast = fast->next;
if( fast != NULL )
{
slow = slow->next;
fast = fast->next;
}
}
*frontRef = source;
*backRef = slow->next;
slow->next = NULL;
}
}
/*Function to print nodes in a given linked list*/
void printList(struct node* node)
{
while( node != NULL )
{
printf("%d ", node->data);
node = node->next;
}
}
/* Function to insert a node at the begining of the linked list*/
void push(struct node** head_ref, int new_data)
{
/*allocate node*/
struct node* new_node = (struct node*)malloc(sizeof(struct node));
/*put in the data*/
new_node->data = new_data;
/*link the old list off the new node*/
new_node->next = (*head_ref);
/*move the head to point to the new node*/
(*head_ref) = new_node;
}
/* Drier program to test above functions*/
int main()
{
/* Start with the empty list */
struct node* res = NULL;
struct node* a = NULL;
/* Let us create a unsorted linked lists to test the functions
Created lists shall be a: 2->3->20->5->10->15 */
push(&a, 15);
push(&a, 10);
push(&a, 5);
push(&a, 20);
push(&a, 3);
push(&a, 2);
/* Sort the above created Linked List */
MergeSort(&a);
printf("\n Sorted Linked List is: \n");
printList(a);
return 0;
}
时间复杂度为O(nLogn)。
转载地址:http://blog.csdn.net/lalor/article/details/7430624
当我们需要对链表进行排序时,由于不能对它的元素进行随机访问,所以更适合使用归并排序,大名鼎鼎的快速排序用到链表上,效率也很低,原因还是在于不能对链表中的元素进行随机访问,同理,采用堆排序更是不可能的事情。
算法具体实现时需要一个指向头节点(链表的第一个节点,链表中不包含额外的一个节点来作头节点)的指针,这是因为在算法实现的时候,不大可能第一个节点正好就是所有元素中最小的一个,则链表的头节点会改变,因此我们需要一个指向头节点的指针来存储不断变化的头节点。
算法思想:
MergeSort(headRef)
1) If head is NULL or there is only one element in the Linked List then return. 2) Else divide the linked list into two halves. FrontBackSplit(head, &a, &b); /* a and b are two halves */ 3) Sort the two halves a and b. MergeSort(a); MergeSort(b); 4) Merge the sorted a and b (using SortedMerge() discussed here) and update the head pointer using headRef. *headRef = SortedMerge(a, b);
代码示例:
#include <stdio.h>
#include <stdlib.h>
/*Link list node*/
struct node
{
int data;
struct node* next;
};
/*function prototype */
struct node* SortedMerge(struct node* a, struct node* b);
void FrontBackSplit(struct node* source, struct node** frontRef, struct node** backRef);
/*sorts the linked list by changing next pointers(not data) */
void MergeSort(struct node** headRef)
{
struct node* head = *headRef;
struct node* a;
struct node* b;
/*base case-- length 0 or 1 */
if((head == NULL) || (head->next == NULL))
{
return;
}
/*Split head into 'a' and 'b' sublists */
FrontBackSplit(head, &a, &b);
/*Recursively sort the sublists */
MergeSort(&a);
MergeSort(&b);
/* answer = merge the two sorted lists together */
*headRef = SortedMerge(a, b);
}
struct node* SortedMerge(struct node* a, struct node* b)
{
struct node* result = NULL;
/* Base cases */
if(a == NULL)
return (b);
else if(b == NULL)
return (a);
/* Pick either a or b recur */
if(a->data <= b->data)
{
result = a;
result->next = SortedMerge(a->next, b);
}
else
{
result = b;
result->next = SortedMerge(a, b->next);
}
return (result);
}
/* UTILITY FUNCTIONS */
/* Split the nodes of the given list into front and back halves,
and return the two lists using the references parameters.
If the length is odd, the extra node shold go in the front list.
Uses the fast/slow pointer strategy. */
void FrontBackSplit(struct node* source, struct node** frontRef, struct node** backRef)
{
struct node* fast;
struct node* slow;
if(source == NULL || source->next == NULL)
{
*frontRef = source;
*backRef = NULL;
}
else
{
slow = source;
fast = source->next;
/* Advance 'fast' two nodes, and advance 'slow' one node */
while(fast != NULL)
{
fast = fast->next;
if( fast != NULL )
{
slow = slow->next;
fast = fast->next;
}
}
*frontRef = source;
*backRef = slow->next;
slow->next = NULL;
}
}
/*Function to print nodes in a given linked list*/
void printList(struct node* node)
{
while( node != NULL )
{
printf("%d ", node->data);
node = node->next;
}
}
/* Function to insert a node at the begining of the linked list*/
void push(struct node** head_ref, int new_data)
{
/*allocate node*/
struct node* new_node = (struct node*)malloc(sizeof(struct node));
/*put in the data*/
new_node->data = new_data;
/*link the old list off the new node*/
new_node->next = (*head_ref);
/*move the head to point to the new node*/
(*head_ref) = new_node;
}
/* Drier program to test above functions*/
int main()
{
/* Start with the empty list */
struct node* res = NULL;
struct node* a = NULL;
/* Let us create a unsorted linked lists to test the functions
Created lists shall be a: 2->3->20->5->10->15 */
push(&a, 15);
push(&a, 10);
push(&a, 5);
push(&a, 20);
push(&a, 3);
push(&a, 2);
/* Sort the above created Linked List */
MergeSort(&a);
printf("\n Sorted Linked List is: \n");
printList(a);
return 0;
}
时间复杂度为O(nLogn)。
貌似MergeSort的时间复杂度为O(nLogn),Split的时间复杂度也为O(nLogn)?当然了,总的时间复杂度还是O(nLogn),但是肯定没有对数组进行归并排序快。
转载地址:http://blog.csdn.net/lalor/article/details/7430624
相关文章推荐
- 利用快速排序对单链表进行排序
- 链表面试题-单链表排序(冒泡,快速,归并)
- Coding interview : 链表排序(选择,插入,快排,归并)
- 用归并排序对链表进行排序
- 单链表的归并、快速排序 C++
- 链表排序--归并排序
- LeetCode147_Insertion Sort List(用插入排序算法对链表进行排序) Java题解
- 链表排序(冒泡、选择、插入、快排、归并、希尔、堆排序)
- C语言数据结构 链表与归并排序实例详解
- 对链表进行排序(归并排序)
- 链表之排序(插入、选择、归并、快速、冒泡)
- 针对有头结点的链表进行排序
- 链表排序(冒泡、选择、插入、快排、归并、希尔、堆排序)
- 用归并排序对链表进行排序
- 链表的归并排序与快速排序
- 采用单链表进行冒泡排序
- 单链表排序(插入与归并)
- C语言单向动态链表程序,实现链表的建立,合并,重新排序,链表元素的插入与删除,以及根据元素成员的值进行元素删除。
- LeetCode-Sort List,链表排序(插入和归并),时间复杂度O(n^2) and O(nlgn)
- 链表排序Sort_List(归并)