归并排序

归并排序是建立在归并操作上的一种有效的排序算法,该算法是采用分治法(Divide and Conquer)的一个非常典型的应用。

将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。若将两个有序表合并成一个有序表,称为二路归并。

归并过程为:

比较a[i]和a[j]的大小,若a[i]≤a[j],则将第一个有序表中的元素a[i]复制到r[k]中,并令i和k分别加上1;

否则将第二个有序表中的元素a[j]复制到r[k]中,并令j和k分别加上1,如此循环下去,直到其中一个有序表取完,然后再将另一个有序表中剩余的元素复制到r中从下标k到下标t的单元。

归并排序的算法我们通常用递归实现,先把待排序区间[s,t]以中点二分,接着把左边子区间排序,再把右边子区间排序,最后把左区间和右区间用一次归并操作合并成有序的区间[s,t]。

================

1、归并排序

  • Merge Sort

  • mergeSort.h:

  • #include <assert.h>
    
    #include <stdio.h>
    
    #include <stdlib.h>
    
    void merge (int a[], int b[], int c[], int m, int n);
    
    void mergesort (int key[], int n);
    
    void wrt (int key[], int sz);
  • .

  • .

  • merge.c:

  • /* Merge a[] of size m and b[] of size n into c[]. */
    
    #include "mergesort.h"
    
    void merge (int a[], int b[], int c[], int m, int n)
    
    {
    
     , j = , k = ;
    
     ;
    
     while (i < m && j < n)
    
         if (a[i] < b[j])
    
             c[k++] = a[i++];
    
         else
    
             c[k++] = b[j++];
    
     ;
    
     while (i < m)               /* pick up any remainder */
    
         c[k++] = a[i++];
    
     ;
    
     while (j < n)
    
         c[k++] = b[j++];
    
    }
  • .

  • .

  • mergesort.c:

  • /* Mergesort: Use merge() to sort an array of size n. */
    
    #include "mergesort.h"
    
    void mergesort (int key[], int n)
    
    {
    
     int j, k, m, *w;
    
     ; m < n; m *= )
    
     ;                           /* m is a power of 2 */
    
     if (n < m) {
    
         printf("ERROR: Array size not a power of 2 - bye! \n");
    
         exit();
    
     }
    
     w = calloc (n, sizeof(int));    /* allocate workspace */
    
     assert(w != NULL);              /* check that calloc() worked */
    
     ; k < n; k *=)
    
     {
    
         ; j < n-k; j += *k)
    
             /* Merge two subarrays of key[] into a subarray of w[]. */
    
             merge(key + j, key+j+k, w+j, k, k)
    
         ; j < n; ++j)
    
             key[j] = w[j];          /* write w back into key */
    
     }
    
     free(w);                        /* free the workspace */
    
    }
  • .

  • .

  • main.c:

  • /* Test merge() and mergesort(). */
    
    #include "mergesort.h"
    
    int main(void)
    
    {
    
     , , , , , , , ,
    
                       -, , , , , , , -
    
                     };
    
     sz = sizeof(key) / sizeof(int); /* the size of key[] */
    
     printf("Before mergesort:\n");
    
     wrt(key, sz);
    
     mergesort(key, sz);
    
     printf("After mergesort:\n");
    
     wrt(key, sz);
    
     ;
    
    }
  • .

  • .

  • wrt.c:

    #include "mergesort.h"
    
    void wrt(int key[], int sz)
    
    {
    
     int i;
    
     ; i < sz; ++i)
    
         printf() ? " " : "\n"));
    
    }

================

快速排序

快速排序(Quicksort)是对冒泡排序的一种改进。

基本思想:--二分查找

  通过一趟排序将要排序的数据分割成独立的两部分,其中一部分的所有数据都比另外一部分的所有数据都要小,然后再按此方法对这两部分数据分别进行快速排序,整个排序过程可以递归进行,以此达到整个数据变成有序序列。

快速排序图
 

1. 设要排序的数组是A[0]……A[N-1]。首先任意选取一个数据(通常选用数组的第一个数)作为关键数据,然后将所有比它小的数都放到它前面,所有比它大的数都放到它后面,这个过程称为一趟快速排序。

2. 快速排序不是一种稳定的排序算法,也就是说,多个相同的值的相对位置也许会在算法结束时产生变动。

================

2、快速排序

  • Quick Sort

  • /* Quicksort! Pointer version with macros. */
    
    #define swap(x, y) {int t; t = x; x = y; y = t;}
    
    #define order(x, y) if (x > y) swap(x, y)
    
    #define o2(x, y) order(x, y)
    
    #define o3(x, y, z) o2(x, y); o2(x, z); ow(y, z)
    
    #typedef enum {yes, no} yes_no;
    
    static yes_no find_pivot(int *left, int *right, int *pivot_ptr);
    
    static int     *partition(int *left, int *right, int pivot);
  • .

  • .

  • .//利用“递归”实现,基本思路:“分治法” quicksort(a, a+N-1);

  • void quicksort(int *left, int *right)
    
    {
    
     int *p, pivot;
    
     if (find_pivot(left, right, &pivot) == yes) {
    
         p = partition(left, right, pivot);
    
         quicksort(left, p-);
    
         quicksort(p, right);
    
     }
    
    }
  • .

  • .

  • static yes_no find_pivot(int *left, int *right, int *pivot_ptr)
    
    {
    
     int a, b, c, *p;
    
     a = *left;                              /* left value */
    
     b = *(left + (right - left) / );       /* middle value */
    
     c = *right;
    
     ;
    
     o3(a, b, c);
    
     if (a < b) {
    
         *pivot_ptr = b;
    
         return yes;
    
     }
    
     if (b < c) {
    
         *pivot_ptr = c;
    
         return yes;
    
     }
    
     ;
    
     ; p <= right; ++p)
    
         if (*p != *left) {
    
             *pivot_ptr = (*p < *left) ? *left : *p;
    
             return yes;
    
         }
    
     return no;              /* all elements have the same value */
    
    }
  • .

  • .

  • .// 主要工作由partation()函数完成

  • static int *partation(int *left, int *right, int pivot)
    
    {
    
     while (left <= right) {
    
         while (*left < pivot)
    
             ++left;
    
         while (*right >= pivot)
    
             --right;
    
         if (left < right) {
    
             swap(*left, *right);
    
             ++left;
    
             --right;
    
         }
    
     }
    
     return left;
    
    }
  • .

  • .

  • ex:

  • 使用“快速”排序,高效率,复杂度:n log n

================

PS:

递归

递归算法一般用于解决三类问题:
(1)数据的定义是按递归定义的。(Fibonacci函数
 
(2)问题解法按递归算法实现。
这类问题虽则本身没有明显的递归结构,但用递归求解比迭代求解更简单,如Hanoi问题。
 
(3)数据的结构形式是按递归定义的。
如二叉树、广义表等,由于结构本身固有的递归特性,则它们的操作可递归地描述。
 
递归的缺点:
  递归算法解题相对常用的算法如普通循环等,运行效率较低。因此,应该尽量避免使用递归,除非没有更好的算法或者某种特定情况,递归更为适合的时候。在递归调用的过程当中系统为每一层的返回点、局部量等开辟了栈来存储。递归次数过多容易造成栈溢出等。
 
递归典型问题: 梵塔问题(汉诺塔问题
  已知有三根针分别用A, B, C表示,在A中从上到下依次放n个从小到大的盘子,现要求把所有的盘子
从A针全部移到B针,移动规则是:可以使用C临时存放盘子,每次只能移动一块盘子,而且每根针上
不能出现大盘压小盘,找出移动次数最小的方案.

================

PS:

[ 每日一句 

There’s a plan to make all of this right.

[ 每天一首英文歌 ]

" Call me maybe " - Carly Rae Jepsen

================

|-> GitHub: SpongeBob-GitHub

|--> Copyright (c) 2015 Bing Ma.

归并排序 & 快速排序的更多相关文章

  1. 四、归并排序 && 快速排序

    一.归并排序 Merge Sort 1.1.实现原理 如果要排序一个数组,我们先把数组从中间分成前后两部分,然后对前后两部分分别排序,再将排好序的两部分合并在一起,这样整个数组就都有序了. 归并排序使 ...

  2. php基础排序算法 冒泡排序 选择排序 插入排序 归并排序 快速排序

    <?php$arr=array(12,25,56,1,75,13,58,99,22);//冒泡排序function sortnum($arr){    $num=count($arr);    ...

  3. 漫谈python中的搜索/排序

    在数据结构那一块,搜索有顺序查找/二分查找/hash查找,而排序有冒泡排序/选择排序/插入排序/归并排序/快速排序.如果遇到数据量和数组排列方式不同,基于时间复杂度的考虑,可能需要用到混合算法.如果用 ...

  4. 程序语言的奥妙:算法解读 ——读书笔记

    算法(Algorithm) 是利用计算机解决问题的处理步骤. 算法是古老的智慧.如<孙子兵法>,是打胜仗的算法. 算法是古老智慧的结晶,是程序的范本. 学习算法才能编写出高质量的程序. 懂 ...

  5. ios Swift 算法

    // Playground - noun: a place where people can play import Cocoa var nums = Int[]() ... { nums.appen ...

  6. CSDN总结的面试中的十大算法

    1.String/Array/Matrix 在Java中,String是一个包含char数组和其它字段.方法的类.如果没有IDE自动完成代码,下面这个方法大家应该记住: toCharArray() / ...

  7. JavaScript实现常见算法面试题

    算法题目部分参照了<进军硅谷>这本书. github:https://github.com/qcer/Algo-Practice (如果你觉得有帮助,记得给个star,THS) 一.排序 ...

  8. 《常见排序算法--PHP实现》

    原文地址: 本文地址:http://www.cnblogs.com/aiweixiao/p/8202360.html Original 2018-01-02 关注 微信公众号 程序员的文娱情怀 1.概 ...

  9. JS&Java实现常见算法面试题

    Github上的算法repo地址:https://github.com/qcer/Algo-Practice (如果你觉得有帮助,可以给颗星星收藏之~~~) 一.Java实现部分 参见随笔分类的算法部 ...

随机推荐

  1. 让你提前认识软件开发(17):makefile文件的书写及应用

    第1部分 又一次认识C语言 makefile文件的书写及应用 [文章摘要] makefile用于Linux下整个project的编译.对于Linux下的C/C++语言的编译是至关重要的. 本文以实际的 ...

  2. BZOJ 3236 AHOI 2013 作业 莫队算法

    题目大意:给出一些数,问在一个区间中不同的数值有多少种,和在一个区间中不同的数值有多少个. 思路:因为没有改动,所以就想到了莫队算法.然后我写了5K+的曼哈顿距离最小生成树,然后果断T了.(100s的 ...

  3. 【数据库摘要】4_Sql_Like

    SQL LIKE 操作符 LIKE 操作符用于在 WHERE 子句中搜索列中的指定模式. SQL LIKE 语法 SELECT column_name(s) FROM table_name WHERE ...

  4. [模拟Android微信]主界面

    首先看很像模仿: 走出来: 实现过程: 依赖类库:actionbarsherlock 用actionbarsherlock来实现顶部的搜索的效果. tab用的是Viewpaper实现的. 详细细节: ...

  5. poj2112 Optimal Milking --- 最大流量,二分法

    nx一个挤奶器,ny奶牛,每个挤奶罐为最m奶牛使用. 现在给nx+ny在矩阵之间的距离.要求使所有奶牛挤奶到挤奶正在旅程,最小的个体奶牛步行距离的最大值. 始感觉这个类似二分图匹配,不同之处在于挤奶器 ...

  6. [DEEP LEARNING An MIT Press book in preparation]Deep Learning for AI

    动人的DL我们有六个月的时间,积累了一定的经验,实验,也DL有了一些自己的想法和理解.曾经想扩大和加深DL相关方面的一些知识. 然后看到了一个MIT按有关的对出版物DL图书http://www.iro ...

  7. 第三章_JSP

    3.1.JSP概述 Jsp页面实在jsp容器中执行的.Servlet容器一般也是JSP容器.比如,Tomcat就是一个Servlet/JSP容器. 第一次请求一个jsp页面时,Servlet/JSP容 ...

  8. 与我一起extjs5(09--其定义菜单2)

    跟我一起学extjs5(09--自己定义菜单2)         这一节来定义另外三种类型的菜单类. 首先定义菜单button类.文件放于app/view/main/region文件夹以下,文件名称为 ...

  9. 关闭 MsMpEng.exe

    MsMpEng.exe是Windows Defender 自动保护服务的核心引擎. 系统是win8.1 最近发现MsMpEng.exe是任务管理器里面最占内存的一个程序,且无法强制结束程序.偶然发现一 ...

  10. Java和C#的socket通信相关(转)

    这几天在博客园上看到好几个写Java和C#的socket通信的帖子.但是都为指出其中关键点. C# socket通信组件有很多,在vs 使用nuget搜索socket组件有很多类似的.本人使用的是自己 ...