数组排序之快排、堆排、归并

快排

三坐标遍历分两半,递归实现快排

#include <iostream>

#include <vector>

#include <algorithm>

using namespace std;

void qs(vector<int>& v,int l,int r) {

if (l >= r) return;

auto pivot = v[r];

auto j = l;//中分位,也是第三游标

for (int i = l;i <= r;i++) {

if (v[i] < pivot) {

swap(v[j++],v[i]);

}

}

swap(v[j],v[r]);//最后一次交换,也是中分必须的

qs(v,l,j-1);

qs(v,j + 1,r);

}

int main()

{

vector<int> v = {9,8,7,6,5,4,3,2,1};

qs(v,0,v.size()-1);

for(auto a:v)cout << a << " ";

return 0;

}

堆排序

先从中间往前遍历调整构造大顶堆,然后交换和调整,实现堆排序

#include<iostream>

#include<vector>

#include <algorithm>

using namespace std;

//调整大顶堆,大的上移,一直下找

void adjust(vector<int> &nums, int b,int e)//[b,e]

{

int f = nums[b];

for(int i = 2*b+1; i <= e; i = 2*i+1) // 往下找大的,往上移

{

if(i < e && nums[i] < nums[i+1]) i++; //指大

if(f >= nums[i]) break;//f是pivot

nums[b] = nums[i],b = i; //大的往上

}

nums[b] = f;

}

int main() //复杂度n*logN

{

vector<int> nums = {49,38,65,97,76,13,27,49,1,100,1010,200};

//构造大顶堆,从中间到前面一直调整大顶堆

for(int i = nums.size() / 2; i >=0; i--)

{

adjust(nums,i,nums.size()-1);

}

for(int i = nums.size()-1; i > 0; i--)//交换和调整大顶堆

{

swap(nums[0],nums[i]);

adjust(nums,0,i-1);

}

for(auto iter:nums) cout<<iter<<" "<<endl;

return 0;

}

//1 13 27 38 49 49 65 76 97##堆排序 cpp

归并排序(两两合并)

[合并K个排序链表](https://leetcode-cn.com/problems/merge-k-sorted-lists)

给你一个链表数组,每个链表都已经按升序排列。

请你将所有链表合并到一个升序链表中,返回合并后的链表。

示例 1:

输入:lists = [[1,4,5],[1,3,4],[2,6]]

输出:[1,1,2,3,4,4,5,6]

解释:链表数组如下:

[

1->4->5,

1->3->4,

2->6

]

将它们合并到一个有序链表中得到。

1->1->2->3->4->4->5->6

示例 2:

输入:lists = []

输出:[]

示例 3:

输入:lists = [[]]

输出:[]

提示:

k == lists.length

0 <= k <= 10^4

0 <= lists[i].length <= 500

-10^4 <= lists[i][j] <= 10^4

lists[i] 按 升序 排列

lists[i].length 的总和不超过 10^4

考虑分治的思想来解这个题(类似归并排序的思路)。把这些链表分成两半,如果每一半都合并好了,那么我就最后把这两个合并了就行了。这就是分治法的核心思想。

但是这道题由于存的都是指针,就具有了更大的操作灵活性,可以不用递归来实现分治。就是先两两合并后在两两合并。。。一直下去直到最后成了一个。(相当于分治算法的那棵二叉树从底向上走了)。

第一次两两合并是进行了k/2次,每次处理2n个值,即2n * k/2 = kn 次比较。

第二次两两合并是进行了k/4次,每次处理4n个值,即4n * k/4 = kn 次比较。

。。。

最后一次两两合并是进行了k/(2^logk)次(=1次),每次处理2^logK * N个值(kn个),即1*kn= kn 次比较。

所以时间复杂度:

O(KN* logK)

空间复杂度是O(1)。

class Solution {

public:

ListNode dummy;

ListNode* mergeKLists(vector<ListNode*>& lists) {

if(lists.empty()){

return nullptr;

}

list<ListNode*> l;

for(auto h:lists)l.emplace_back(h);

while(l.size() > 1){

ListNode* l1 = l.front();

l.pop_front();

ListNode* l2 = l.front();

l.pop_front();

l.emplace_back(mergeTwoLists(l1,l2));

}

return l.front();

}

ListNode *mergeTwoLists(ListNode *l1, ListNode *l2) {

if(!l1 || !l2) return l1? l1:l2;

ListNode *pre = &dummy;

while (l1 && l2)

{

if(l1->val <= l2->val)

{

pre ->next = l1;

l1 = l1->next;

}

else

{

pre->next = l2;

l2 = l2->next;

}

pre = pre->next;

}

if (l1) pre->next = l1;

else pre->next = l2;

return dummy.next;

}

};

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值