• 排序


    以下程序均与sort进行一百万数据对拍十次(有误请告知)

    选择排序

    #include <bits/stdc++.h>
    using namespace std;
    #define ll int
    const int INF = INT_MAX;/// int的极限值
    const int maxn = 1e5+7;
    int mine = -INF; /// int 里面的最小值
    int M[maxn];
    int main()
    {
        int n;
        scanf("%d",&n);
        for(int i=1;i<=n;++i)
        {
            scanf("%d",M+i);/// 输入
        }
        for (int i=1;i<=n;++i)
        {
            int t = mine;
            int idx =-1;
            for (int j=1;j<=n-i+1;++j)/// 从后往前找到大的元素放到后一个位置 (不包含已经排好序的)
            ///  (n-i+1)| 已经排好序.......
            {
                if (M[j] > t)
                {
                   t = M[j];
                   idx  = j;
                }
            }
            ///cout<<t<<' '<<idx<<endl;
            swap(M[idx],M[n-i+1]);///交换第I大的值放到未排序的最后
        }
        for (int i=1;i<=n;++i)
        {
            printf("%d ",M[i]);
        }
        puts("");
        return 0;
    }
    

    希尔排序

    #include <bits/stdc++.h>
    using namespace std;
    const int maxn = 1e5+7;
    int n;
    int A[maxn];
    void shell_sort()
    {   
        /*
             希尔排序   区别于之前的插入排序  希尔排序就是在原来的基础之上   首先按照一定的间隔进行插入排序
             缩小间隔 然后使得数组相对有序 最后进行间隔为1 的插入排序 也就是最基础的插入排序  
        */
        for(int di = floor(n/2);di>=1;di = floor(di/2)) ///每次缩半  向上取整
        {
            for (int i=di+1;i<=n;++i)/// 间隔为di的插入排序
            {
               A[0] = A[i];
               if (A[i] < A[i-di])
               {   
                   int j;
                   for (j=i-di;j>0&&A[0]<A[j];j-=di)
                   {
                        A[j+di] = A[j];
                   }
                    A[j+di] = A[0];
               }  
            } 
        }
        for (int i=1;i<=n;++i)
        {
            printf("%d ",A[i]);
        }
        puts("");
    }
    
    int main()
    {
        scanf("%d",&n);
        for (int i=1;i<=n;++i)scanf("%d",A+i);
        shell_sort();
        return 0;
    }
    

    冒泡排序

    #include <bits/stdc++.h>
    using namespace std;
    const int maxn = 1e5+4;
    int M[maxn];
    int main()
    {
        int n;
        scanf("%d",&n);
        for (int i=1;i<=n;++i)
        {
            scanf("%d",M+i);
        }
        for (int i=1;i<=n-1;++i)
        {
            for (int j=1;j<=n-i;++j)
            {
                if (M[j]>M[j+1])
                    swap(M[j],M[j+1]);/// 其实冒泡排序的方法跟选择排序的很类似
                /// 这里就是每次从n个中选出最大值 不就是两个两个比较选出最大值   
                ///  从n-1个数中选出次大值   然后这里的话就是把这个n-i+1个数里面的最大值往后移
                /// 但是这样每次都需要交换(交换是需要时间的)  所以选择排序就将这里优化了
                /// 直接找n-i+1里面的最大值 ,然后将他放在n-i+1的位置上交换一次就可以了
            }
        }
        for (int i=1;i<=n;++i)
        {
            printf("%d ",M[i]);
        }
        puts("");
        return 0;
    }
    

    快速排序

    #include <bits/stdc++.h>
    using namespace std;
    const int maxn = 1e5+7;
    int M[maxn];
    int n;
    /*
        快速排序的思路就是找到一个中枢轴 然后将大于中枢轴的数往中枢轴后面放,否则放在他之前
        然后遍历所有的轴ok  (分治算法)
    
    */
    void  quick_sort(int ll,int rr)
    {
        if (ll>=rr) return ;
        int l =ll;
        int r =rr; 
        int t = M[ll];/// 直接以ll作为中枢轴,那么此时的l是空出来的  
        /// 此时的方法就是往两边丢数,最后产生的分界线放中枢轴
        while (l<r)
        {
            while ((l<r) && M[r] >= t) --r;///先从右往左丢  
            if (l<r)
            {
                M[l] = M[r];
                ++l;
            }
            while ((l<r) && M[l] <= t) ++l;///从左往右丢
            if (l<r)
            {
                M[r] = M[l];
                --r; 
            }
        }
        M[l] = t;/// 最后一定是l>=r  假设最后是从右往左丢,那么r的数值丢到l,l++, l == r
        ///  假设最后是从左往右丢  那么l的数值丢到r,--r  l==r   所以这里l r都可以
        quick_sort(ll,l-1);///继续丢他的左右子区间  直至区间长度为1 这样就每次将n长的区间做两半处理
        quick_sort(l+1,rr);
    }
    int main()
    {
        scanf("%d",&n);
        for (int i=1;i<=n;++i)
        {
            scanf("%d",M+i);
        }
        ///cout<<1<<endl;
        quick_sort(1,n);
        for (int i=1;i<=n;++i)
        {
            printf("%d ",M[i]);
        }
        puts("");
        return 0;
    }
    
    

    堆排序

    #include <bits/stdc++.h>
    using namespace std;
    const int maxn = 1e5+7;
    int M[maxn];
    int n;
    /*
       堆排序的构造原理就是多棵二叉树的集合体  那么这棵二叉树满足 父亲节点大于(或者小于)所有的子根节点、
       这样就保证根节点一定大于(或者小于)这棵子树的任何元素
       然后这样构造的好处就是每次这棵树的总根就是最大(最小)值
       但是他只满足于局部最优  ,局部最优从下往上就能够造成整体最大
    */
    int update_heap_sort(int s,int sum)/// 当前根节点   需要更新的长度
    {
        int R = M[s];///最上面的那个根节点
        for (int j=2*s;j<=sum;j*=2)///首先比较当前根所在的根和两个子节点  j记录子树的编号 s记录当前这棵子树的根
        {
            if ((j+1)<=sum && M[j]<M[j+1]) ++j;///记录j的位置  看看是否存在右子树 如果要往右子树方向交换就++
            if (R > M[j]) break;///已经是最大的了就无须操作
            else 
            {
                M[s] = M[j];/// 先将大的数从子节点上升到根节点  
                s = j;/// 但是又要满足堆的条件 任意一个根节点都要大于两个子节点 所以要将刚刚交换的小数往下沉 继续更新
            }
        }
        M[s] = R;///现在的s已经移动到合适的位置,可以将原来被交换的数放到s根上
    }
    void heap_sort()
    {
        for (int i=n/2;i>=1;--i)/// n/2代表就是最后一个节点n的根n/2
        {
            update_heap_sort(i,n);///对于所有的根节点  从下往上更新最大值
            /// 保证当前任意的根节点的数大于子节点
        }
        for (int k=n;k>1;--k)
        {
            swap(M[1],M[k]);/// M[1] 表示他是最大值 因为M[1]在更新堆的时候就是最大值了
            update_heap_sort(1,k-1);///最后的数值已经排好序了所以大根堆堆顶被移除就需要更新
        }
    }
    
    void out()
    {
        for (int i=1;i<=n;++i)
        {
           printf("%d ",M[i]);
        }   
        puts("");
    }
    
    int main()
    {
        scanf("%d",&n);
        for (int i=1;i<=n;++i) scanf("%d",M+i);
        heap_sort();
        out();
        return 0;
    }
    

    插入排序(数组)

    /* 
       插入排序
       数组实现 
       将原来的数组划分为一个有序组和无序组  有序|无序  将无序数组的插入进有序数组就会使得无序变少有序增多
    */
    #include <bits/stdc++.h>
    using namespace std;
    const int  maxn = 1e5;///10^5
    int a[maxn];
    int main()
    {
        int n;
        cin>>n;
        for (int i=1;i<=n;++i)
        {
           cin>>a[i];
        }
        for (int i=2;i<=n;++i)///剩余的n-1个数组成的无序组  
        {
            a[0] = a[i];///将所有待选择的数放在第一位进行比较,因为之后的数字移动会挤占当前位置
            int j;
            for (j=i-1;j>=1;--j)///从后往前边比对边移动   此时是在有序组中给无序组新来的数据找位置
            {
                if (a[0]>=a[j])break;
                a[j+1] = a[j];
            }
            a[j+1] = a[0];///给i找到一个合适的位置进行插入
        }
        for (int i=1;i<=n;++i)
        {
           if (i!=n) printf("%d ",a[i]);
           else printf("%d
    ",a[i]);
        }
        return 0;
    }
    

    插入排序(链表)

    /*
       插入排序链表实现
    */
    #include <bits/stdc++.h>
    using namespace std;
    const int maxn = 1e5+7;
    struct Node {
       struct Node *next;
       int idx;
    };
    int main()
    {
        int n;
        scanf("%d",&n);
        Node *Head;
        Head  = (struct Node*)malloc(sizeof(struct Node));///   构建一个表头 ,储存一个空值 
        struct Node *p;
        p = Head;
        for (int i=1;i<=n;++i)
        {
            int x;
            scanf("%d",&x);
            struct Node *q;
            q = (struct Node*)malloc(sizeof(struct Node));
            q->idx = x;
            p->next = q;///不断的将新的q插入到p之后
            p = p->next;
        }
        p->next = NULL;/// 表尾为空
        if (Head->next)///存在第一个数据才排序
        {
            struct Node *p;
            p = Head->next->next;///记录下一个位置,防止被覆盖
            Head->next->next = NULL;///链表截断 一个有序组,一个无序组
            while (p)
            {
                struct Node *q = p->next;
                struct Node *t = Head;
                while (t->next&&p->idx>t->next->idx)t = t->next;///移动,从前往后依次比对
                p->next = t->next;///比对完成,完成插入
                t->next = p;
                p = q;
            }
        }
        for (struct Node *T=Head->next;T;T=T->next)
        {
            printf("%d ",T->idx);
        }
        return 0;
    }      
    

    插入排序(静态链表)

    #include <bits/stdc++.h>
    using namespace std;
    const int maxn = 1e5+7;
    int M[maxn];
    int N[maxn];///变化之前的链数组
    int W[maxn];///变化之后的链数组
    int n;
    /*
       插入排序的主要思路就是一个有序组和一个无序组   
       A1 | A2  A3  A4  A5   
       然后的话将右边的无序区的数组一个一个的插入左边的有序组
    */
    void init()
    {
        N[0] = 1;
        ///处理下边界,此处相当于表头节点
        for (int i=1;i<=n;++i)  N[i] = i+1;
        ///初始化  ,当前和下一个相连的下标就是当前下标+1
        N[n] = 0;
        ///链表最后就指向0   
    }
    /*
         静态链表
         M数据负责储存原始数据
         N数组相当于指针,指出下一个
         N[i]记录的是和i相连的下一个区块的下标
    */
    void out(int x)
    {
        if (x)
        {
          printf("%d ",M[x]);
          out(N[x]);
        }
    }///  输出函数
    int main()
    {
        scanf("%d",&n);
        init();
        for (int i=1;i<=n;++i)
        {
          scanf("%d",M+i); 
          /// cout<< M[i]<<endl;
        }
        if (N[0])
        {
            int p = 2;
            N[1] = 0; ///类似于之前的链表,只不过相当于将next指针换成一个数组   首先将链表的头截断
            while (p)
            {
                int t = 0;
                int q = N[p];///  记录下p的下一个坐标 防止丢失
                while (N[t] && M[p]>M[N[t]]) t = N[t];/// 找到有序组中可以插入的位置  找到的就是可以插入的位置的(前面那个)
                N[p] = N[t]; /// 首先取代t,将t的后面的那一段接给p
                N[t] = p;/// t的下一个就是p
                p = q;///无序组中的下一个
            }
         }
         out(N[0]);///输出
         cout<<endl;
        
         return 0;
    }
    

    静态链表转有序数组

    #include <bits/stdc++.h>
    using namespace std;
    const int maxn = 1e5+7;
    int M[maxn];
    int N[maxn];///变化之前的链数组
    int W[maxn];///变化之后的链数组
    int n;
    /*
       插入排序的主要思路就是一个有序组和一个无序组   
       A1 | A2  A3  A4  A5   
       然后的话将右边的无序区的数组一个一个的插入左边的有序组
    */
    void init()
    {
        N[0] = 1;
        ///处理下边界,此处相当于表头节点
        for (int i=1;i<=n;++i)  N[i] = i+1;
        ///初始化  ,当前和下一个相连的下标就是当前下标+1
        N[n] = 0;
        ///链表最后就指向0   
    }
    /*
         静态链表
         M数据负责储存原始数据
         N数组相当于指针,指出下一个
         N[i]记录的是和i相连的下一个区块的下标
    */
    void out(int x)
    {
        if (x)
        {
          printf("%d ",M[x]);
          out(N[x]);
        }
    }///  输出函数
    int main()
    {
        scanf("%d",&n);
        init();
        for (int i=1;i<=n;++i)
        {
          scanf("%d",M+i); 
          /// cout<< M[i]<<endl;
        }
        if (N[0])
        {
            int p = 2;
            N[1] = 0; ///类似于之前的链表,只不过相当于将next指针换成一个数组   首先将链表的头截断
            while (p)
            {
                int t = 0;
                int q = N[p];///  记录下p的下一个坐标 防止丢失
                while (N[t] && M[p]>M[N[t]]) t = N[t];/// 找到有序组中可以插入的位置  找到的就是可以插入的位置的(前面那个)
                N[p] = N[t]; /// 首先取代t,将t的后面的那一段接给p
                N[t] = p;/// t的下一个就是p
                p = q;///无序组中的下一个
            }
         }
         
         ///out(N[0]);///输出
         ///cout<<endl;
         ///  之前的已经按照静态链表的数组进行储存
         ///  现在需要将数组变成有序数组  就不需要N数组的辅助
         for (int k=0;k<=n;++k)
         {
             W[k] = N[k];///  进行复制
         }
         int i = 1;
         int j = N[0];
         for (i = 1;i < n;++i)
         {
           ///cout<<i<<' '<<j<<endl;
           if (i==j)  ///  i是摆放的位置  j是摆放的数据来源的下标  相同就直接下一个
           {
             j = N[j];
           }
           else if(i<j) /// 如果当前的在后面 直接交换  已经摆好位置的i被后面的M[j]取代,
            ///  那么下次如果有之前的寻找的话,此时将W【i】变为J代表该位置已经被移动到j位置
           {
             swap(M[i],M[j]);
             W[j] = W[i];
             W[i] = j;
             j = N[j];  
           }
           else 
           {
              int t = j;/// j本身不能动,因为要从这里寻找下一个位置
              while (i>t) t=W[t];    ///  i>j 说明我现在需要交换的数据来源于之前的j,但是之前的位置按照w[t]一直寻找
              swap(M[i],M[t]);/// 跳到 i<j 的位置  然后进行交换   
              W[i] = t;  
              j = N[j];///  但是原本的位置还是需要保留   因为每次都是根据之前的原来的连接关系来求解的
           }
         }
         for (int t=1;t<=n;++t)
         {
           printf("%d ",M[t]);
         }
         puts("");
         return 0;
    }
    

    归并排序 递归实现

    #include <bits/stdc++.h>
    using namespace std;
    #define ll long long
    const int maxn = 1e5+7;
    int op[maxn];///实际数组
    int M[maxn];/// 中转的数组
    void merge_sort(int l,int mid,int r)
    {
        int i = l;
        int j = mid+1;
        int t = 0;/// 中转数组的下标
        while (i <= mid && j<= r)
        {
            if (op[i]<=op[j])///   如果当前小于直接就放到左边
            {
                M[t] = op[i];
                ++i;
                ++t;
            }
            else
            {
                M[t] = op[j];
                ++t;
                ++j;
            }
        }
            while (i<=mid)
            {
                M[t] = op[i];
                ++t;++i;
            }
            while (j<=r)///剩余的放回
            {
                M[t] = op[j];
                ++j,++t;
            }
            int rear = 0;
            int tmp = l;
            while (tmp<=r)
            {
                op[tmp] = M[rear];/// 赋值回原来的数组
                ++rear;
                ++tmp;
            }
    
    }
    void M_sort(int l,int r)
    {
        if (l<r)
        {
            int mid = (r-l)/2+l;
            M_sort(l,mid);///  左区间进行分解
            M_sort(mid+1,r);///左右区间进行分解
            merge_sort(l,mid,r);/// 最后将区间进行归并
            ///  由于是首先先进行分解递归然后归并的所以就是
            /// 首先分解为2 2^2 2^3开始归并
        }
    }
    int main()
    {
        int n;
        cin>>n;
        for (int i=1;i<=n;++i)cin>>op[i];
        M_sort(1,n);
        for (int i=1;i<=n;++i)
        cout<<op[i]<<' ';
        return  0;
    }
    
    
    齐芒行,川锋明!
  • 相关阅读:
    C#如何生成CHM帮助文件
    使用WebBrowser控件播放Flash网页相关问题解决方法
    C# AnimateWindow与WindowState同时使用的效果
    C#读取计算机串口
    C#基础概念二十五个问题
    C# ini 文件读取方法
    JSP读出MYSQL数据库时的乱码问题解决方案
    世界编程大赛头名程序
    比较著名的.net技术论坛网址(含国外的)
    How to Install Linux, Apache, MySQL, PHP (LAMP) stack on CentOS 6
  • 原文地址:https://www.cnblogs.com/qimang-311/p/14095525.html
Copyright © 2020-2023  润新知