您的位置:首页 > 其它

归并排序之数组和链表

2017-04-25 13:49 417 查看

归并排序之数组篇

Step1: 合并两个有序的数组

void mergearray (int arr[] , int first , int mid , int last , int temp[]) {
// temp数组是临时用来储存已经排好序的数组
int i = first , j = mid + 1 ;
// i , j分别储存两个数组两部分的开头
int m = mid , n = last ;
// m储存中间值,i部分的末尾;n储存末尾值,j部分的末尾
int k = 0 ;
// 储存temp数组的的位置

while (i <= m && j <= n) { // 两部分数组都未遍历完的时候
if (arr[i] <= arr[j])
temp[k ++] = arr[i ++] ;
else if (arr[i] > arr[j])
temp[k ++] = arr[j ++] ;
}
// i , j两部分数组至少有一个已经遍历完,如果遍历完,就不会进入while循环
while (i <= m) // 如果i部分数组还未遍历完
temp[k ++] = arr[i ++] ;
while (j <= n) // 如果j部分数组还未遍历完
temp[k ++] = arr[j ++] ;

for (int i = 0 ; i < k ; i ++)
arr[first + i] = temp[i] ;
// 将排好序的数组复制回原数组,因为temp数组是临时的
}


Step2: 将数组一分为二,不断递归

void mergesort (int arr[] , int first , int last , int temp[]) {
if (first == last) return ;
// 只有一个元素的时候,就是已经排好序的,直接返回
if (first < last) {
int mid = (first + last) / 2 ;
// 找到中间点
mergesort (arr , first , mid , temp) ;
// 对左边排好序
mergesort (arr , mid + 1 , last , temp) ;
// 对右边排好序
mergearray (arr , first , mid , last , temp) ;
// 将左边,右边合并进入一个数组
}
}


Step3: 实现更加人性化的接口(更方便客户使用)

bool mergeSort (int arr[] , int length) {
int* p = new int [length] ;
// 用作临时储存数组
if (p == NULL || length == 0) {
return false ;
}
mergesort (arr , 0 , length - 1 , p) ;
delete [] p ;
return true ;
}


归并排序之链表篇

[title3]有这样一个链表[/title3]

struct node {
int data;
struct node* next;
node(int data = 0, struct node* next = NULL) : data(data), next(next) {}
} ;


Step1: 将两个有序链表合并成一个链表

node* mergeSortedList (node* h1 , node* h2) {
// 注意这里要返回链表指针作为参数,否则其他函数无法获得已经排好序的链表
node* newhead ;
if (h1 == NULL) return h2 ;
if (h2 == NULL) return h1 ;
// 如果有一个链表为空,那么直接返回另外一个链表指针作为头即可
if (h1 -> data <= h2 -> data) {
newhead = h1 ;
h1 = h1 -> next ;
}
else {
newhead = h2 ;
h2 = h2 -> next ;
}
// 找到新的头指针,并且把那个向后移一个
node* temp = newhead ;
// 防止newhead被修改
while (h1 && h2) {
if (h1 -> data <= h2 -> data) {
temp -> next = h1 ;
temp = temp -> next ;
h1 = h1 -> next ;
}
else {
temp -> next = h2 ;
temp = temp -> next ;
h2 = h2 -> next ;
}
}
// 如果h1没排完:
while (h1) {
temp -> next = h1 ;
h1 = h1 -> next ;
temp = temp -> next ;
}
// 如果h2没排完:
while (h2) {
temp -> next = h2 ;
temp = temp -> next ;
h2 = h2 -> next ;
}
return newhead ;
}


Step2: 将链表一分为二(注意怎么找到链表的中间点)

node* mergeSort (node* head) {
// 注意这里需要有返回值,原因是要在递归过程把结果传递下去
if (head == NULL || head -> next == NULL) return head ;
// 如果是空,直接返回head
node* fast = head , *slow = head ;
while (fast -> next && fast -> next -> next) {
fast = fast -> next -> next ;
slow = slow -> next ;
}
// 利用fast的检索速度是slow的两倍来找到中间点
node* leftHead = head ;
node* rightHead = slow -> next ;
slow -> next = NULL ;
// 十分十分重要的是,要把左边的尾巴断掉,即置空
leftHead = mergeSort (leftHead) ;
// 排好左边链表
rightHead =  mergeSort (rightHead) ;
// 排好右边链表
return mergeSortedList (leftHead , rightHead) ;
// 返回合并后的链表
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: