您的位置:首页 > 编程语言 > C语言/C++

C/C++ 数组,链表排序(平均时间复杂度 O(nlogn))归并、快速、堆、希尔之归并排序

2018-03-04 15:53 549 查看

归并排序:

给定一个int数组A以及大小n,请返回排序后的数组;

核心思想:

是建立在归并操作上的一种有效的排序算法,该算法是采用分治法(Divide and Conquer)的一个非常典型的应用。将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。若将两个有序表合并成一个有序表,称为二路归并。
归并排序的一般步骤为:
1)将待排序数组(链表)取中点并一分为二;
2)递归地对左半部分进行归并排序;
3)递归地对右半部分进行归并排序;
4)将两个半部分进行合并(merge),得到结果。

采用递归的过程进行归并排序,并使用一个与A大小相同的辅助数组空间B,大家都知道递归是一个进栈和出栈的过程。
1、递归调用归并排序过程将数组折半查找:
1.1、递归调用数组A前一半,和后一半,返回条件是开始索引>=结束索引
(递归调用这一步是压栈过程,直到每一半的大小划分为1)
1.2、调用将前一半、后一半的数组,归并并且排好序成为一个数组的函数merger()。
(这一步就是出栈,并且从划分为1的划分慢慢变大,但是划分的数组因为调用merger()函数已经成为有序数组)(这个是重点理解)
2、merger()函数归并思想体现在这(将前一半a1数组和后一半a2数组,合并并排序,其实a1和a2经过前面的递归已经有序):

b618
2.1、将a1和a2从头开始比较,谁小,就把谁存到B数组里面(重点)
2.2、将a1或a2中还没比较的,直接复制到数组B中
2.3、将排序好的B数组复制给A数组



A[i]和A[j]进行比较谁小,就把它放到B中,然后小的下标向后移动,另一个不动,循环比较;
直到有一个先结束(A[j]先结束),另外一个(A[i]的6,7值)还没结束,直接将没结束的后面每比较的直接复制到B中。

代码:

class MergeSort {
public:
//第一步:分配B数组
int* mergeSort(int* A, int n) {

int *B = (int*)malloc(sizeof(int) * n);

QuickSort(A, B, 0, n-1);

free(B);

return A;

}
//第三步:merger()函数
void merger(int *A, int *B, int start, int mid, int end){
int i = start;
int j = mid+1;
int k = start;
//将a1和a2从头开始比较,谁小,就把谁存到B数组里面
while(i <=mid && j <=end){
if(A[i] < A[j]){
B[k++] = A[i++];
}
else{
B[k++] = A[j++];
}
}
//将a1或a2中还没比较的,直接复制到数组B中
while(i != mid+1){
B[k++] = A[i++];
}

while(j != end+1){
B[k++] = A[j++];
}
//将排序好的B数组复制给A数组
k=start;
while(k <= end){
A[k++] = B[k];
//k++;  = 为从右到左的运算  不能写成 A[k] = B[k++],因为这样k不是从0开始,k++已经让k+1过了A[k]中的k是1;
}
}

//第二步:递归调用归并排序
void QuickSort(int *A, int *B, int start, int end){
if(start >= end)
return;

int mid = (start + end) /2;

QuickSort(A, B, start, mid);
QuickSort(A, B, mid+1, end);

merger(A, B, start, mid, end);

}

};
main调用:#include <iostream>
using namespace std;
int main(){
int AAA[]={1,3,6,9,2,5,4,8,7};
MergeSort M;
int *b=M.mergeSort(AAA,9);
for(int i=0;i<9;i++){
    cout<<b[i]<<endl;
}

return 0;
}

链表:

采用快慢指针找中点:快慢指针思路,快指针一次走两步,慢指针一次走一步,快指针在链表末尾时,慢指针恰好在链表中点
时间复杂度为:O(nlogn),原因一样
空间复杂度为:O(1),因为没有借助其他空间。

代码:

class Solution {
public:
ListNode* findMiddle(ListNode* head){
ListNode* chaser = head;
ListNode* runner = head->next;//一定要用next
while(runner != NULL && runner->next != NULL){
chaser = chaser->next;
runner = runner->next->next;
}
return chaser;
}

ListNode* mergeTwoLists(ListNode* l1, ListNode* l2) {
if(l1 == NULL){
return l2;
}
if(l2 == NULL){
return l1;
}
ListNode* dummy = new ListNode();//空结构
ListNode* head = dummy;
while(l1 != NULL && l2 != NULL){
if(l1->val > l2->val){
head->next = l2;
l2 = l2->next;
}
else{
head->next = l1;
l1 = l1->next;
}
head = head->next;
}
if(l1 == NULL){
head ->next = l2;
}
if(l2 == NULL){
head->next = l1;
}
return dummy->next;
}

ListNode* sortList(ListNode* head) {
if(head == NULL || head ->next == NULL){
return head;
}
ListNode* middle = findMiddle(head);
ListNode* right = sortList(middle->next);//这就是上面为啥要用next的原因
middle -> next = NULL;//截断
ListNode* left = sortList(head);
return mergeTwoLists(left, right);
}
};
main()调用#include <iostream>
using namespace std;
struct ListNode{
int val;
struct ListNode* next;

};
int main(){
ListNode *list=(ListNode *)malloc(sizeof(ListNode));
list->val=2;
list->next=NULL;
//可以用循环
ListNode *l=list;
ListNode *p=(ListNode *)malloc(sizeof(ListNode));
p->val=4;
list->next=p;
list=list->next;

ListNode *lo=(ListNode *)malloc(sizeof(ListNode));
lo->val=5;
list->next=lo;
list=list->next;

ListNode *q=(ListNode *)malloc(sizeof(ListNode));
q->val=3;
list->next=q;
list=list->next;

list->next=NULL;

Solution s;
ListNode* ss =s.sortList(l);
while(ss!=NULL){
cout<<ss->val<<endl;
ss=ss->next;
}

return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐