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; }
相关文章推荐
- C/C++ 数组排序(平均时间复杂度 O(nlogn))归并、快速、堆、希尔之希尔排序
- C/C++ 数组排序(平均时间复杂度 O(nlogn))归并、快速、堆、希尔之堆排序
- C/C++ 数组排序(平均时间复杂度 O(nlogn))归并、快速、堆、希尔之快速排序
- C++实现几种常用的时间复杂度为O(nlogn)的排序方法:归并排序、快速排序、堆排序、希尔排序
- 快速排序[平均时间复杂度O(NlogN)]
- O(nlogn)时间复杂度 链表排序
- 数据结构(C#)--冒泡、插入、快速、堆、归并、希尔、选择各种排序排序过程比较以及各种排序的所用时间的对比
- 快速排序的时间复杂度nlogn是如何推导的??
- 归并排序平均时间复杂度O(NlogN)
- 算法学习 - 链表之归并排序_O(1)空间_O(NlogN)时间_C++
- 快速排序的时间复杂度nlogn是如何推导的??
- 单链表的归并、快速排序 C++
- 快速排序的时间复杂度nlogn是如何推导的??
- 对链表排序 要求时间 复杂度为 O(nlogn) 空间复杂度为常量
- 数组排序(插入、选择、希尔、堆、归并、快速、冒泡)
- LeetCode 148. Sort List--O(nlogn)时间复杂度和常数空间复杂度给链表排序
- Java-时间复杂度为O(nlogn)的排序算法(快速排序, 归并排序, 堆排序, 希尔排序)
- 数据结构各种排序法及核心思想(冒泡、鸡尾酒、选择、插入、二分法、希尔、堆、归并、快速)
- 六种排序方法的学习(直接插入、希尔、冒泡、快速、选择、归并)
- C++快速排序、归并排序