• 分治思想_归并排序_各种写法和思路(待续)


    摸鱼了一个星期没更,现在补回来。上星期基本上就是邻接ddl(周一),套板子或者用现成sort修修补补过的,

    今天是周六,是时候检验一下是不是真的完全会了,顺便解决一些当时没有想通的问题

    先说归并排序

    归并的思路,我觉得应该是很容易理解的,这里就不赘述,唯一难的就是把这个—再归并再排序—的模板自己写出来,

    网上有很多模板,比较著名的是《算法导论》上的那个借助两个媒介数组实现的,以及借助一个媒介数组实现的,

    停!这里其实就是第一个分歧了,似乎为了方便,大部分板子都是有辅助空间的,但是实际上还有一个原地存储不使用额外辅助空间的办法,只是写法会有所不同

    • 对于递归的思路来说,整个过程主要是一个自顶向下,再自底向上的过程

        分解成,递归分割到底,然后归并返回,返回时对上一个归并子区间两两排序合并,

    • 对于更简洁的过程,其实只有自底向上的过程,就是所谓的非递归实现

        不用考虑分割,直接实现各个部分的自底向上排序,

    https://blog.csdn.net/acingdreamer/article/details/53925072?utm_source=blogxgwz8(比较详细的解释)

    的,自然合并排序的思路,https://blog.csdn.net/m0_37787222/article/details/79856252

    OK。这里是第二个分歧点,下面来讨论最核心的部分,合并两个有序区间该怎么操作,

    对于 两个数组,1 2 4 和 3 4 6,固定一个,比如前面那个,然后一对一,从小到大,a1,b1,大就往后找,小就安插前面,

    比如现在b1放在a2前面,然后接着b2,从a2开始找,

    从1到n来比,小的放进媒介数组tmp,大的继续和剩下的比,比完之后,会有多余的,多余的补充到后面,

    再把已经操作过的tmp中的元素再放回目标移动数组a,

    这时就体现媒介数组的好处,如果原地存储需要整体移动,很麻烦,当然用stack或者set  insert可能稍微好一点,

    附上本人的代码,重点是第十九行

     1 #include <iostream>
     2 #include <cstdio>
     3 #include <cstring>
     4 #include <algorithm>
     5 using namespace std;
     6 typedef long long ll;
     7 const int Max=1e6+2;
     8 int a[Max];
     9 int t[Max];
    10 
    11 void m1(int a[],int from,int to) {
    12     if(from==to)return;
    13     //int mid=(from+to)>>1;
    14     int mid=(from+to)/2;
    15     //int mid=f+(f-t)/2
    16 
    17     //先分割,
    18     m1(a,from,mid);
    19     m1(a,mid+1,to);
    20 
    21     //分割得到的是区间脚标f,t,mid的状态,最底为f=mid,t=mid+1的极限状态
    22 
    23     //再合并,放入中间数组保存
    24 
    25     int x=from;
    26     int y=mid+1;
    27     int g=1;
    28     while(x<=mid||y<=to) {
    29         /*这个边界是错误的,因为y>to之后继续在第二个if进行比较
    30         if(y>to||a[x]<=a[y]) {//
    31             t[g++]=a[x++];
    32         }
    33         if(x>mid||a[x]>a[y]) {
    34             t[g++]=a[y++];
    35         }
    36         */
    37 
    38         if(y>to||(x<=mid&&y<=to&&a[x]<=a[y])) {
    39             t[g++]=a[x++];
    40         }
    41         if(x>mid||(x<=mid&&y<=to&&a[x]>a[y])) {
    42             t[g++]=a[y++];
    43         }
    44 
    45     }
    46     //多余的不能忽略
    47     g--;
    48     x=from;
    49     for(int i=1; i<=g; i++)a[x++]=t[i];
    50 }
    51 
    52 /*
    53 
    54 5
    55 5 1 3 2 4
    56 6
    57 5 3 2 2 1 6
    58 7
    59 1 2 5 8 2 4 7
    60 8
    61 1 5 6 3 13 5 2 9
    62 
    63 */
    64 
    65 
    66 
    67 int main () {
    68     int n;
    69     while(~scanf("%d",&n)) {
    70         for(int i=1; i<=n; i++)scanf("%d",&a[i]);
    71 
    72         m1(a,1,n);
    73         //for(int i=1; i<=n; i++)printf("%d ",a[i]);
    74         puts("");
    75         //m2();
    76         //    m3();
    77 
    78     }
    79 
    80 
    81     return 0;
    82 }
    View Code

    下面说说非递归实现, 说白了就是直接自底向上划分区间

    重点是如何用循环划分区间后提取边界脚标,那比较简单的想法就是把比较的两个区间的长度作为变量,每次从1开始,

    1v1的比较,得到区间长度最大为2最小为1的有序区间,

    然后2v2,得到长度最大为4最小为2的有序区间,

    然后4v4,得到长度最大为8最小为4的有序区间,

    。。。以此类推

    难点在于有些区间长度直接加不够,需要另外讨论,关键点在于

    merge操作限定了mid必须小于to,不能等于,因此也不能等于n,因此上限是mid小于n

    以下为非递归代码,m2+merge实现

      1 #include <iostream>
      2 #include <cstdio>
      3 #include <cstring>
      4 #include <algorithm>
      5 using namespace std;
      6 typedef long long ll;
      7 const int Max=1e6+2;
      8 int a[Max];
      9 int t[Max];
     10 
     11 void m1(int a[],int from,int to) {
     12     if(from==to)return;
     13     //int mid=(from+to)>>1;
     14     int mid=(from+to)/2;
     15     //int mid=f+(f-t)/2
     16 
     17     //先分割,
     18     m1(a,from,mid);
     19     m1(a,mid+1,to);
     20 
     21     //分割得到的是区间脚标f,t,mid的状态,最底为f=mid,t=mid+1的极限状态
     22 
     23     //再合并,放入中间数组保存
     24 
     25     int x=from;
     26     int y=mid+1;
     27     int g=1;
     28     while(x<=mid||y<=to) {
     29         /*这个边界是错误的,因为y>to之后继续在第二个if进行比较
     30         if(y>to||a[x]<=a[y]) {//
     31             t[g++]=a[x++];
     32         }
     33         if(x>mid||a[x]>a[y]) {
     34             t[g++]=a[y++];
     35         }
     36         */
     37 
     38         if(y>to||(x<=mid&&y<=to&&a[x]<=a[y])) {
     39             t[g++]=a[x++];
     40         }
     41         if(x>mid||(x<=mid&&y<=to&&a[x]>a[y])) {
     42             t[g++]=a[y++];
     43         }
     44 
     45     }
     46     //多余的不能忽略
     47     g--;
     48     x=from;
     49     for(int i=1; i<=g; i++)a[x++]=t[i];
     50 }
     51 //非递归实现
     52 void merge(int from,int mid,int to) {
     53     int x=from,y=mid+1;
     54     int g=1;
     55     while(x<=mid||y<=to) {
     56         if(y>to||(x<=mid&&y<=to&&a[x]<=a[y])) {
     57             t[g++]=a[x++];
     58         }
     59         if(x>mid||(x<=mid&&y<=to&&a[x]>a[y])) {
     60             t[g++]=a[y++];
     61         }
     62     }
     63     g--;
     64     x=from;
     65     for(int i=1; i<=g; i++)a[x++]=t[i];
     66 }
     67 /*
     68 
     69 5
     70 5 1 3 2 4
     71 6
     72 5 3 2 2 1 6
     73 7
     74 1 2 5 8 2 4 7
     75 8
     76 1 5 6 3 13 5 2 9
     77 
     78 */
     79 
     80 
     81 
     82 
     83 
     84 void m2(int n) {
     85     //以区间长度为变量,是活动的
     86     //区间长度从1-2-4-直到n
     87 
     88     for(int i=2; i<n; i*=2) {
     89         int j=1;
     90         while(j<=n) {
     91             int from=j;
     92             int mid=j+i-1;
     93             if(j+i*2-1<=n) {
     94                 int to=j+i*2-1;//记得-1
     95                 merge(from,mid,to);
     96             } else if(i+j-1<n) {
     97                 int to=n;
     98                 merge(from,mid,to);
     99             } else if(i+j-1>=n) {
    100                 break;
    101             }
    102             j+=(i*2);
    103             //    j+=(i*2+1);想太多搞错边界,
    104             printf("i == %d
    ",i);
    105 
    106             for(int i=1; i<=n; i++)printf("%d ",a[i]);
    107             puts("");
    108 
    109         }
    110     }
    111 }
    112 
    113 
    114 
    115 int main () {
    116     int n;
    117     while(~scanf("%d",&n)) {
    118         for(int i=1; i<=n; i++)scanf("%d",&a[i]);
    119 
    120         m2(n);
    121         //for(int i=1; i<=n; i++)printf("%d ",a[i]);
    122         puts("");
    123         //m2();
    124         //    m3();
    125 
    126     }
    127 
    128 
    129     return 0;
    130 }
    View Code
    老实一点,可爱多了
  • 相关阅读:
    网络摄像头监控中什么情况下需要使用流媒体转发服务器?
    流媒体播放器播放h264编码视频与h265编码视频哪个更清晰?
    RTMP推流视频流媒体服务如何实现网络传输?
    web视频直播服务器更改端口号后录像功能失效问题解决
    互联网视频直播/点播流媒体服务器使用http和rtmp做点播时有什么区别?
    视频互联网直播/点播服务器中关于内容分发CDN的相关问题汇总
    网页直播系统推流端和拉流端都有哪些环节?
    自建视频流媒体服务器需要满足哪些条件?
    线上课堂教育行业选择互动直播时有哪些直播方案?
    互联网直播点播平台在进行iframe直播分享时如何禁止本地视频自动播放?
  • 原文地址:https://www.cnblogs.com/KID-yln/p/12636211.html
Copyright © 2020-2023  润新知