分治算法(二)

大家都知道选择排序和冒泡排序,这两个排序都是双重for循环,时间复杂度为O(n^2),显然效率都是比较低的,而运用分治思想的归并排序和快速排序会更高效一些。

1、归并排序

1)原理:假设初始序列含有n个记录,则可以看成是n个有序子序列,每个子序列的长度为1,然后两两归并,得到[n/2]([x]表示不小于x的最小整数)个长度为2或1的有序子序列;再两两归并,……,如此重复,直至得到一个长度为n的有序序列为止,这种排序方法成为2路归并排序。(摘自《大话数据结构》)

可见其运用了典型的分治思想,①分解②求解③合并。刚开始学习这个算法时,我感觉分开排序和一起排序没什么区别,但在实现算法时,会发现n个一起排序的话要用双重for循环,而分开排再合并会高效的多,下面看一下实现的代码。

2)参考代码

#include <iostream>
#include <cstdio>
using namespace std;
int a[10]={2,3,1,5,34,21,12,4,10,6};
int b[10];
void Merge(int a[],int s,int m,int e,int tmp[]);
void Mergesort(int a[],int s,int e,int tmp[]);
int main()
{
    int size=sizeof(a)/sizeof(int);
    Mergesort(a,0,size-1,b);
    for(int i=0;i<size;i++){
        printf("%d ",a[i]);
    }
    return 0;
}
void Mergesort(int a[],int s,int e,int tmp[]){
    if(s<e){
        int m=s+(e-s)/2;
        Mergesort(a,s,m,tmp);
        Mergesort(a,m+1,e,tmp);
        Merge(a,s,m,e,tmp);
    }
}
void Merge(int a[],int s,int m,int e,int tmp[]){
    int p1=s;
    int p2=m+1;
    int p=0;
    while(p1<=m&&p2<=e){
        if(a[p1]<a[p2]){
            tmp[p++]=a[p1++];
        }
        else{
            tmp[p++]=a[p2++];
        }
    }
    while(p1<=m){
        tmp[p++]=a[p1++];
    }
    while(p2<=e){
        tmp[p++]=a[p2++];
    }
    //注意e和s已经变了,刚开始写成了i<size
    for(int i=0;i<e-s+1;i++){
        a[s+i]=tmp[i];
    }

}

根据原理得,这十个数会先一个和一个比,然后合成两个,然后两个和两个比,一直到合成十个排序就完成了。

3)时间复杂度推导:

摘自:http://www.icourse163.org/learn/PKU-1001894005#/learn/content?type=detail&id=1002874892&sm=1

中国大学MOOC程序设计与算法,郭炜

2快速排序

1)基本思想:通过一趟排序将待排记录分割成独立的两部分,其中一部分记录的关键字均比另一部分的记录的关键字小,则可分别对这两部分记录继续进行排序,以达到整个序列有序的目的。

其基本思想也是根据分治算法来的,分解,求解,合并。像归并排序一样光看原理,感觉看不出来该种排序的高效,其实我觉得算法的巧妙更多的是在程序每个细节的代码实现中。

2)参考代码

#include <iostream>
#include <cstdio>
using namespace std;
int a[10]={29,2,3,12,9,76,34,16,7,45};
void QuickShort(int a[],int s,int e);
int main()
{
    QuickShort(a,0,9);
    for(int i=0;i<10;i++){
        printf("%d ",a[i]);
    }
    return 0;
}
void QuickShort(int a[],int s,int e){//s指向要排序列的第一个元素,e指向最后一个
if(s>=e){//临界条件:当两个指针指向同一个数时,说明排完了
    return;
}
int k=a[s];//让k等于s指向的值
int i=s;
int j=e;
while(i!=j){//下面比较的while循环不要忘了让j>i即得到前一半和后一半的下标,也是跳出下面循环的边界
    while(j>i&&a[j]>k){//先从j指向的数开始和k比较,小于k就交换值
        j--;
    }
    swap(a[i],a[j]);
    while(j>i&&a[i]<=k){//交换后k就变成了a[j]的值
        i++;
    }
    swap(a[i],a[j]);
}
    QuickShort(a,s,i);
    QuickShort(a,i+1,e);
}
时间: 2024-10-27 12:53:26

分治算法(二)的相关文章

五种常用的算法设计技巧之二:分治算法

一,介绍 分治算法主要包含两个步骤:分.治.分,就是递归地将原问题分解成小问题:治则是:在解决了各个小问题之后(各个击破之后)合并小问题的解,从而得到整个问题的解 二,分治递归表达式 分治算法一般都可以写出一个递归表达式:比如经典的归并排序的递归表达式:T(N)=2T(N/2)+O(N) T(N)代表整个原问题,采用了分治解决方案后,它可以表示成: ①分解成了两个规模只有原来一半(N/2)的子问题:T(N/2) ②当解决完这两个子问题T(N/2)之后,再合并这两个子问题需要的代价是 O(N) 递

基于分治的二维平面最近点对算法实现

摘要: 网上有很多关于分治方法求最近点对的讨论,但是没有完整的可运行代码,本文主要对于该问题介绍一完整的可运行代码, 供有兴趣者参考. 正文: 作为对比,我们也同时实现了最近点对的枚举解法,具体的主函数如下: #include<stdio.h> #include<stdlib.h> #include "node.h" void initList(node* p) { p[0].x= 2.0; p[0].y= 1.0; p[1].x= 1.0; p[1].y= 2

五大算法之分治算法

一.基本思想 当我们求解某些问题时,由于这些问题要处理的数据相当多,或求解过程相当复杂,使得直接求解法在时间上相当长,或者根本无法直接求出.对于这类问题,我们往往先把它分解成几个子问题,找到求出这几个子问题的解法后,再找到合适的方法,把它们组合成求整个问题的解法.如果这些子问题还较大,难以解决,可以再把它们分成几个更小的子问题,以此类推,直至可以直接求出解为止.这就是分治策略的基本思想. 二.二分法 利用分治策略求解时,所需时间取决于分解后子问题的个数.子问题的规模大小等因素,而二分法,由于其划

数据结构与算法二

1.课程安排表: 1. 线性表 2. 字符串 3. 栈和队列 4.树 5.查找 6.排序 7.暴力枚举法 8.广度优先搜索 9.深度优先搜索 10.分治 11.贪心 12.动态规划 13.图 14.数学方法与常见模型 15.大整数运算 16. 基础功能 2.   编程技巧: 1.把较大的数组放在main 函数(全局变量)外,作为全局变量,这样可以防止栈溢出,因为栈的大小是有限制的.GCC (C编译器) 段错误 2.如果能够预估栈,队列的上限,则不要用stack,queue,使用数组来模拟,这样速

分治算法(思想)在数据结构中的应用

分治算法: 简单的概括就是将暂时不能解决的大问题分成许多入门的子问题, 如果子问题还是不能解决的话则继续分成子问题,直到子问题小到 可以解决为止的规模,原问题即是子问题的合并. PartOne: 用分治法打印数组a[L,......,R]. 分析: 一个循环就可以了,但是分治算法来解决该怎么做呢? 如果待打印的序列长度为 1,则可以直接打印; 如果待打印的序列长度为 N,则可将其划分为两部分; 第一部分是 1, 后N - 1 是另一个划分,以此类推,直到数组长度是 1. void print(i

五大常用算法----贪心、动态规划、分支限界、分治算法和回溯算法

五大常用算法之一:贪心算法 所谓贪心算法是指,在对问题求解时,总是做出在当前看来是最好的选择.也就是说,不从整体最优上加以考虑,他所做出的仅是在某种意义上的局部最优解. 贪心算法没有固定的算法框架,算法设计的关键是贪心策略的选择.必须注意的是,贪心算法不是对所有问题都能得到整体最优解,选择的贪心策略必须具备无后效性,即某个状态以后的过程不会影响以前的状态,只与当前状态有关. 所以对所采用的贪心策略一定要仔细分析其是否满足无后效性. 五大常用算法之二:动态规划算法 五大常用算法之三:分支限界算法

算法学习——分治算法

这是从网上查到的概念资料,先收来~ 一.基本概念 在计算机科学中,分治法是一种很重要的算法.字面上的解释是“分而治之”,就是把一个复杂的问题分成两个或更多的相同或相似的子问题,再把子问题分成更小的子问题……直到最后子问题可以简单的直接求解,原问题的解即子问题的解的合并.这个技巧是很多高效算法的基础,如排序算法(快速排序,归并排序),傅立叶变换(快速傅立叶变换)…… 任何一个可以用计算机求解的问题所需的计算时间都与其规模有关.问题的规模越小,越容易直接求解,解题所需的计算时间也越少.例如,对于n个

lanczos算法及C++实现(三)实对称三对角阵特征值分解的分治算法

本文属作者原创,转载请注明出处 http://www.cnblogs.com/qxred/p/dcalgorithm.html 本系列目录: lanczos算法及C++实现(一)框架及简单实现 lanczos算法及C++实现(二)实对称阵奇异值分解的QR算法 lanczos算法及C++实现(三)实对称三对角阵特征值分解的分治算法 0. 参考文献 https://en.wikipedia.org/wiki/Divide-and-conquer_eigenvalue_algorithm A. Mel

算法系列之常用算法之一----分治算法

一.基本概念 在计算机科学中,分治法是一种很重要的算法.分治算法,字面上的解释是"分而治之",分治算法主要是三点: 1.将一个复杂的问题分成两个或更多的相同或相似的子问题,再把子问题分成更小的子问题----"分" 2.将最后子问题可以简单的直接求解----"治" 3.将所有子问题的解合并起来就是原问题打得解----"合" 这三点是分治算法的主要特点,只要是符合这三个特点的问题都可以使用分治算法进行解决(注意用词,是"