排序 O(nlogn)

1.堆排序是一种优秀的排序算法,时间复杂度O(nlogn),主要思想是用数组构造一个最大堆,满足跟节点的value>子节点的value,然后将堆顶元素(value最大)与最后一个叶子节点交换,再调整堆,使其满足最大堆的性质,重复上述步骤n-1次后就得到一个有序序列。

#include<iostream>
#include<cstdio>
#include<cstring>
#define MAX 111111
#define LEFT(i) (i << 1)
#define RIGHT(i) (i << 1|1)
using namespace std; 
int a[MAX], Heap_Size, a_Length; 
void Max_Heapify(int i){
    int largest, l, r; 
    l = LEFT(i); 
    r = RIGHT(i); 
    if(l <= Heap_Size && a[l] > a[i]) largest = l; 
    else largest = i; 
    if(r <= Heap_Size && a[r] > a[largest]) largest = r; 
    if(largest != i){
        int temp = a[i]; 
        a[i] = a[largest]; 
        a[largest] = temp; 
        Max_Heapify(largest); 
    }
    return; 
}
void Build_Heap(){
    for(int i = a_Length/2; i >= 1; i --)
        Max_Heapify(i); 
    return; 
}
void Heap_Sort(){
    Build_Heap(); 
    for(int i = a_Length; i >= 2; i --){
        int temp = a[1]; 
        a[1] = a[i]; 
        a[i] = temp; 
        Heap_Size--; 
        Max_Heapify(1); 
    }
    return ; 
}
int main(){
    freopen("data.cpp", "r", stdin); 
    freopen("out.cpp", "w", stdout); 
    while(~scanf("%d", &a_Length)){
        Heap_Size = a_Length; 
        for(int i = 1; i <= a_Length; i ++) scanf("%d", a+i); 
        Heap_Sort(); 
        printf("Length = %d\n", a_Length); 
        for(int i = 1; i < a_Length; i ++) printf("%d ", a[i]); 
        printf("%d\n\n\n", a[a_Length]); 
    }
    return 0; 
}

2.快速排序:主要思想就是随机选定一个数x,以该数为基准,将数组划分,左边都小于或等于它,右边都大于它,这样就将数组划分成左右两部分,而数x则是处于正确位置,然后再重复上述过程分别处理左右部分,直到数组有序。时间复杂度O(nlogn).


#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#define MAX 111111
using namespace std; 
int a[MAX], a_length; 
int Rand_Partition(int p, int r){
    int x = a[r], i = p-1; 
    for(int j = p; j < r; j ++){
        if(a[j] <= x){
            i ++; 
            int temp = a[i]; 
            a[i] = a[j]; 
            a[j] = temp; 
        }
    }
    a[r] = a[i+1]; 
    a[i+1] = x; 
    return i+1; 
}
void Qucik_Sort(int p, int r){
    if(p < r){                //与调用Rand_Partition()函数效果一样;
        int i = p-1; 
        for(int j = p; j < r; j ++){
            if(a[j] <= a[r]){
                i ++; 
                swap(a[i], a[j]); 
            }
        }
        swap(a[r], a[i+1]); 
        int q = i+1;             //end;
        /* int q = Rand_Partition(p, r); */  
        Qucik_Sort(p, q-1); 
        Qucik_Sort(q+1, r); 
    }
}
int main(){
    freopen("data.cpp", "r", stdin); 
    freopen("Quick_sort_out.cpp", "w", stdout); 
    while(~scanf("%d", &a_length)){
        printf("Length = %d\n", a_length); 
        for(int i = 0; i < a_length; i ++) scanf("%d", a+i); 
        Qucik_Sort(0, a_length-1); 
        for(int i = 0; i < a_length-1; i ++) printf("%d ", a[i]); 
        printf("%d\n\n\n", a[a_length-1]); 
    }
    return 0; 
}

3.归并排序,采用分治策略,主要思想是假定数组a和b已经是有序的,那么可以在O(n)的时间内将他们合并成一个有序序列,现在将数组平均分成两部分,但这两部分并不是有序的,因此需要再次将这两个部分再分,使问题规模逐渐变小,继续递归划分,当子数组足够小时(即只有一个元素),可以直接求解,因为此时一个元素就是有序的。然后就可以合并这两个部分了,合并完之后就形成一个局部有序序列(我们最终要得到整个有序序列),此时向上回溯与其他有序部分进行合并,当回溯到跟节点时,整个序列就合并完毕,因此得到一个有序序列。分治策略一般分为三步:(1):分解原问题使问题规模变小以便我们直接处理,对于上述问题就是将原序列分解,当分解到子序列只有一个元素时就可直接求解(因为一个元素的序列已经是有序的了);(2)治,即解决问题;(3)合并,将子问题解决之后要向上合并从而得到原问题的解。分治策略一般使用递归来实现。

#include<stdio.h>
#include<string.h>
int a[1000005]; 
int l[100005]; 
int r[100005]; 
void merge(int p, int mid, int q)
{
    int nl = mid - p + 1; 
    int nr = q - mid; 
    int i, j, k; 
    for(i = 0; i < nl; i ++)
        l[i] = a[p+i]; 
    for(i = 1; i <= nr; i ++)
        r[i - 1] = a[mid+i]; 
    l[nl] = 1 << 30; 
    r[nr] = 1 << 30; 
    i = 0; 
    j = 0; 
    for(k = p; k <= q; k ++)
    {
        if(l[i] <= r[j])
            a[k] = l[i++]; 
        else
            a[k] = r[j++]; 
    }
}

void merge_sort(int l, int r)
{
    if(l < r)
    {
        int mid = (l + r) >> 1; 
        merge_sort(l, mid); 
        merge_sort(mid + 1, r); 
        merge(l, mid, r); 
    }
}

int main(int argc, char const *argv[]) 
{
    int n, i; 
    freopen("data.cpp", "r", stdin); 
    freopen("Merge_out.cpp", "w", stdout); 
    while(~scanf("%d", &n))
    {
        printf("Length = %d\n", n); 
        for(i = 0; i < n; i ++)
            scanf("%d", &a[i]); 
        merge_sort(0, n-1); 
        for(i = 0; i < n-1; i ++)
            printf("%d ",a[i]);
        printf("%d\n\n\n", a[i]); 
    }
    return 0; 
}

4.最后一个是用二叉搜索树通过中序遍历得到的有序序列,时间复杂度也是O(nlogn)较简单和容易理解。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<stack>
using namespace std; 
typedef struct Node{
    int key; 
    Node *left; 
    Node *right; 
    Node(){
        left = NULL; 
        right = NULL; 
    }
}Node; 
Node *root; 
stack<Node*>s; 
void Insert(int key){
    Node *tmp = new Node(); 
    tmp->key = key; 
    Node *ff = root;
    Node *flag = NULL; 
    while(ff){
        flag = ff; 
        if(key <= ff->key) ff = ff->left; 
        else ff = ff->right; 
    }
    if(flag == NULL){
        root = new Node(); 
        root->key = key; 
        return; 
    }
    if(flag->key >= key) flag->left = tmp; 
    else flag->right = tmp; 
}

void Visist_Treee_1(Node *tmp){                                
    if(tmp){
        Visist_Treee_1(tmp->left); 
        printf("%d ", tmp->key); 
        Visist_Treee_1(tmp->right); 
    }
}

void Visist_Treee_2(Node *tmp){
    while(!s.empty()) s.pop(); 
    s.push(tmp); 
    while(!s.empty()){
        Node *p = s.top(); 
        while(p) s.push(p->left), p = p->left; 
        s.pop();
        if(!s.empty()){
            Node *q = s.top(); 
            printf("%d ", q->key);
            s.pop();
            s.push(q->right); 
        }
    }
}

int main(){
    int n, temp; 
    freopen("data.cpp", "r", stdin); 
    freopen("Binary_Tree_out.cpp", "w", stdout); 
    while(~scanf("%d", &n)){
        root = NULL; 
        printf("Length = %d\n", n); 
        for(int i = 0; i < n; i ++){
            scanf("%d", &temp); 
            Insert(temp); 
        }
        Visist_Treee_1(root); 
        printf("\n\n\n"); 
        Visist_Treee_2(root); 
    }
}



转载于:https://www.cnblogs.com/wangzhili/p/3950279.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值