zoukankan      html  css  js  c++  java
  • 排序 第K大等问题总结

    在公司面试时,当场写排序比较多,虽然都是老掉牙的问题,还是要好好准备下

    快速排序,以第一个元素为关键词比较,每次比较结束,关键词都会去到最终位置上

    //7 3 2 9 8 3 4 6
    //7 3 2 9 8 5 4 6
    //7 5 2 9 8 3 4 6
    
    #include<stdio.h>
    int s[10999];
    void mysort(int left,int right){
        if(left>=right)return;
    
        int mid,key=s[left];
        int ll=left,rr=right;
        while(ll<rr){
            while(s[rr]>=key&&ll<rr)rr--;
            s[ll]=s[rr];
            while(s[ll]<=key&&ll<rr)ll++;
            s[rr]=s[ll];
        }s[ll]=key;
        mysort(left,ll-1);
        mysort(ll+1,right);
    }
    
    int main(){
        int n;
        while(scanf("%d",&n)!=EOF){
            int i,k;
            for(i=1;i<=n;i++){
                scanf("%d",&s[i]);
            }
    
            mysort(1,n);
            for(i=1;i<=n;i++){
                printf("%d
    ",s[i]);
            }
        }
    
        return 0;
    }
    View Code

    改了下,更通俗了些

    #include<stdio.h>
    #include<time.h>
    #include<iostream>
    using namespace std;
    
    int shu[909]={0,5,2,9,7,3,6,4,8,1};
    
    void quickSort(int left,int right){
        if(left>=right) return ;
        int ll=left,rr=right;
        int temp=shu[left];
        while(ll<rr){
            while(temp<=shu[rr]&&rr>left)rr--;
            while(temp>=shu[ll]&&ll<right)ll++;
            if(ll>=rr)break;
            swap(shu[ll],shu[rr]);
        }
        swap(shu[left],shu[rr]);
        quickSort(left,rr);
        quickSort(rr+1,right);
    }
    
    int main(){
        int i,n=100;
        for(i=1;i<=n;i++){
            shu[i]=rand()%1000;
            printf("%d ",shu[i]);
        }
        quickSort(1,n);
        
        for(i=1;i<=n;i++){
            printf("%d ",shu[i]);
        }
        getchar();
    }
    View Code

    第k大的元素,其实就是在快速排序的基础上对递归做了个限制,就是对一边进行递归, 比如Kth的位置在key的左边,我们就递归(left,ll-1);反之(ll+1,right)

    //7 3 2 9 8 3 4 6    1
    //7 3 2 9 8 3 4 6    2
    //7 3 2 9 8 3 4 6    3
    //7 3 2 9 8 3 4 6    4
    //7 3 2 9 8 3 4 6    7
    
    #include<stdio.h>
    int s[10999];
    
    int findKth=0,kth;
    void kth_element(int left,int right){
        if(left>=right)return;
        if(findKth==1){
            return ;
        }
    
        int mid,key=s[left];
        int ll=left,rr=right;
        while(ll<rr){
            while(s[rr]>=key&&ll<rr)rr--;
            s[ll]=s[rr];
            while(s[ll]<=key&&ll<rr)ll++;
            s[rr]=s[ll];
        }s[ll]=key;
        if(kth<ll)
            kth_element(left,ll-1);
        else if(kth>ll)
            kth_element(ll+1,right);
        else{
            findKth=1;
            return ;
        }
    }
    
    
    int main(){
        int n;
        while(scanf("%d",&n)!=EOF){
            int i,k;
            for(i=1;i<=n;i++){
                scanf("%d",&s[i]);
            }
            scanf("%d",&kth);
            findKth=0;
            kth_element(1,n);
            printf("%d
    ",s[kth]);
    
            //mysort(1,n);
            for(i=1;i<=n;i++){
                printf("%d ",s[i]);
            }printf("
    ");
        }
    
        return 0;
    }
    View Code

    改的适合自己的模板

    #include<stdio.h>
    #include<time.h>
    #include<iostream>
    using namespace std;
    
    int shu[909]={0,5,2,9,7,3,6,4,8,1};
    int key,ret;
    int ok;
    
    void Kth(int left,int right){
        if(ok==1)return;
        if(left>=right) return ;
        int ll=left,rr=right;
        int temp=shu[left];
        while(ll<rr){
            while(temp<=shu[rr]&&rr>left)rr--;
            while(temp>=shu[ll]&&ll<right)ll++;
            if(ll>=rr)break;
            swap(shu[ll],shu[rr]);
        }
        swap(shu[left],shu[rr]);
        if(rr==key){
            ok=1;
            ret=shu[rr];
            return ;
        }
        
        if(key<rr)
            Kth(left,rr);
        else
            Kth(rr+1,right);
    }
    
    int main(){
        int i,n=20;
        srand(time(NULL));
        for(i=1;i<=n;i++){
            shu[i]=rand()%1000;
            printf("%d ",shu[i]);
        }printf("
    ");
        
        key=9;
        ok=0;
        Kth(1,n);
        
        for(i=1;i<=n;i++){
            printf("%d ",shu[i]);
        }printf("
    ");
        printf("kth = %d
    ",ret);
        getchar();
    }
    View Code

    根据堆的定义,堆是一个完全二叉树,手写了个大顶堆,其实堆就两个操作,入堆(需要向上调整),出堆(需要向下调整),堆排序就是依次把堆顶元素出堆

    向上调整不需要选择,因为祖先只有一个;向下调整需要选择是从左子树还是右子树,因为儿子可能有两个

    #include<iostream>
    #include<cstdio>
    #include<time.h>
    using namespace std;
    double test[10009],s[10009];
    
    int head_size;
    void head_push(int k,double temp){//入堆其实是一个向上调整的过程
        int n=k;
        s[k]=temp;
        while(n!=1){
            if(s[n/2]<s[n]){
                swap(s[n/2],s[n]);
            }
            n=n/2;
        }
        return ;
    }
    
    void head_pop(){//堆顶元素出堆其实是向下调整的过程
        int n=1;
        s[1]=s[head_size+1];
        while(n*2<=head_size){
            if(n*2+1<=head_size){//右儿子存在
                if(s[n]>=s[2*n+1]&&s[n]>=s[2*n])break;//父节点比两个儿子都大退出
                if(s[2*n+1]>s[2*n]){ //右儿子比左儿子大
                    swap(s[n],s[2*n+1]);
                    n=n*2+1;
                }else{ //左儿子比右儿子大
                    swap(s[n],s[2*n]);
                    n=n*2;
                }
            }
            else{//只存在左儿子
                if(s[n]>=s[2*n])break;//父节点比左儿子大退出
                swap(s[n],s[2*n]);
                n=n*2;
            }
        }
        return;
    }
    
    void headSort(double *input,int left,int right){
        int i;
        head_size=0;
        for(i=left;i<=right;i++){
            head_size++;
            head_push(head_size,input[i]);
        }
        
        for(i=left;i<=right;i++){
            input[i]=s[1];
            head_size--;
            head_pop();
        }
        
        int half=(left+right)>>1;
        double temp;
        for(i=left;i<=half;i++){//因为是大顶堆,所以要调整
            temp=input[i];input[i]=input[right-i+1];input[right-i+1]=temp;
        }
    
    }
    
    int main(){
        freopen(" data.txt","r",stdin);
        time(NULL);
        int i;
    
        for(i=1;i<=10000;i++){
            scanf("%lf",&test[i]);
        }
        headSort(test,1,10000);
    
        printf("第1个:%lf
    ",test[1]);
        printf("第10个:%lf
    ",test[10]);
        printf("第100个:%lf
    ",test[100]);
        printf("第1000个:%lf
    ",test[1000]);
        printf("第10000个:%lf
    ",test[10000]);
    
        return 0;
    }
    View Code

    //发现原来的堆排序写的有点罗嗦,改了一下

    #include<iostream>
    #include<stdio.h>
    using namespace std;
    
    int head_size;
    int s[109]={0,2,8,1,3,9,4,7,6,5};
    int temp[109];
    
    //大顶堆
    void shiftUp(int a[],int i){
        while(i>1&&a[i]>a[i/2]){
            swap(a[i],a[i/2]);
            i>>=1;
        }
    }
    
    void shiftDown(int a[],int i,int n){
        while((i*2)<=n){
            i<<=1;
            if((i+1)<=n && a[i+1]>a[i])i++;
            if(a[i]>a[i/2])swap(a[i],a[i/2]);
            else break;
        }
    }
    
    void headSort(int a[],int n){
        head_size=n;
        int i;
        for(i=1;i<=n;i++){
            shiftUp(s,i);
        }
        for(i=1;i<=n;i++){
            temp[i]=s[1];
            s[1]=s[n+1-i];
            head_size--;
            shiftDown(s,1,head_size);
        }
    
        for(i=1;i<=n;i++){
            s[i]=temp[i];
        }
    }
    
    
    int main(){
        int n=9,i;
        headSort(s,n);
        for(i=1;i<=n;i++){
            printf("%d
    ",s[i]);
        }
    
        return 0;
    }
    View Code

     //这个数据量可以控制

    #include<stdio.h>
    #include<time.h>
    #include<iostream>
    using namespace std;
    
    int shu[909]={0,5,2,9,7,3,6,4,8,1};
    int newShu[909];
    
    void shiftUp(int a[],int n){
        int i=n,next;
        while(i>1){
            next=i>>1;
            if(a[i]>a[next])
                swap(a[i],a[next]);
            i=next;
        }
    }
    
    void shiftDown(int a[],int n){
        int i=1;
        while((i<<1)<=n){
            i=i<<1;
            if((i+1)<=n&&a[i+1]>a[i])i++;
            if(a[i]>a[i/2])swap(a[i],a[i/2]);
        }
    }
    
    void headSort(int n){
        int i;
        for(i=1;i<=n;i++){
            shiftUp(shu,i);
        }
        for(i=1;i<=n;i++){
            newShu[i]=shu[1];
            shu[1]=shu[n-i+1];
            shiftDown(shu,n-i);
        }
    }
    
    int main(){
        int i,n=100;
        srand(time(NULL));
        for(i=1;i<=n;i++){
            shu[i]=rand()%1000;
            printf("%d ",shu[i]);
        }printf("
    ");
    
        headSort(n);
        
        for(i=1;i<=n;i++){
            printf("%d ",newShu[i]);
        }printf("
    ");
    
        getchar();
    }
    View Code

    希尔排序是插入排序的一种变形,是步长不短缩小的插入排序

    #include<iostream>
    #include<cstdio>
    #include<time.h>
    using namespace std;
    double test[10009] ;
    
    void shellsort(double *s,int left,int right) {//希尔排序是插入排序的一种变形,步长逐渐缩小的插入排序
        for (int step = right/ 2;step>0; step/=2) {
           for (int i = step; i <=right; i++) {
               double temp = s[i];
               int j = i;
               while (j >= step && temp < s[j - step]) {
                  s[j] = s[j - step];
                  j -= step;
               }
               s[j] = temp;
           }
        }
    }
    int main(){
        freopen(" data.txt","r",stdin);
        time(NULL);
        int i;
    
        for(i=1;i<=10000;i++){
            scanf("%lf",&test[i]);
        }
        shellsort(test,1,10000);
    
        printf("第1个:%lf
    ",test[1]);
        printf("第10个:%lf
    ",test[10]);
        printf("第100个:%lf
    ",test[100]);
        printf("第1000个:%lf
    ",test[1000]);
        printf("第10000个:%lf
    ",test[10000]);
    
        return 0;
    }
    View Code

     /*插入排序与希尔排序的实例比较*/

    希尔排序有时被叫做缩减增量排序(diminishing increment sort),使用一个序列h1,h2,h3……这样一个增量序列。只要h1=1时,任何增量序列都是可以的。但有些可能更好。对于希尔排序为什么会比直接插入排序快的原因,我们可以来看一个比较极端的例子:
    
    假如对于一个数组{87654321}以从小到大的顺序来排。直接插入排序显然是很悲剧的了。
    
    它的每次排序结果是这样的:
    
    7, 8, 6, 5, 4, 3, 2, 1
    
     
    
    6, 7, 8, 5, 4, 3, 2, 1
    
     
    
    5, 6, 7, 8, 4, 3, 2, 1
    
     
    
    4, 5, 6, 7, 8, 3, 2, 1
    
     
    
    3, 4, 5, 6, 7, 8, 2, 1
    
     
    
    2, 3, 4, 5, 6, 7, 8, 1
    
     
    
    1, 2, 3, 4, 5, 6, 7, 8
    
     
    
    然后我们来看看Shell排序会怎样处理,一开始步长为4
    
    数组分为8, 7, 6, 5和4, 3, 2, 1
    
    首先是8和4进行比较,交换位置。
    
    变成了4, 7, 6, 5和8, 3, 2, 1
    
    同理7和3,6和2,5和1也是样的,所以当步长为4时的结果是:
    
    4, 3, 2, 1, 8, 7, 6, 5
    
    可以看到,大的数都在后边了。
    
    接下来的步长为2
    
    这一步过程就多了很多:
    
    一开始是4和2进行比较,交换,得到:
    
    2, 3, 4, 1, 8, 7, 6, 5
    
    3和1比较,交换,得到:
    
    2, 1, 4, 3, 8, 7, 6, 5
    
    接下来是4和8,3和7,这两个比较没有元素交换。接下来8和6,7和5就需要交换了。所以步长为2时的结果就是:
    
    2, 1, 4, 3, 6, 5, 8, 7
    
    可以明显地感觉到,数组变得“基本有序”了。
    
    接下来的步长1,变成了直接插入排序。手动模拟一下就可以发现,元素的交换次数只有四次!这是相当可观的。也由此我们可以得到一个基本的事实:对于基本有序的数组,使用直接插入排序的效率是很高的!
    转自:http://www.cnblogs.com/yjiyjige/archive/2013/08/13/3256138.html
    View Code

    归并排序,思考将两个有序数列变成一个有序数列的过程,归并就是由小到大重复这个过程,最终使数组有序

    #include<iostream>
    #include<cstdio>
    #include<time.h>
    using namespace std;
    double test[10009],temp[10009];
    
    void unsort(double *s,int left,int right){
    
        int mid=(left+right)>>1;
        if(mid-left>=1)unsort(s,left,mid);
        if(right-mid>=2)unsort(s,mid+1,right);
        
        int i,p1=left,p2=mid+1;
        for(i=left;i<=right;i++){//两个有序数组变成一个有序数组
            if(p1>mid){
                temp[i]=s[p2];
                p2++;
                continue;
            }
            if(p2>right){
                temp[i]=s[p1];
                p1++;
                continue;
            }
            if(s[p1]<=s[p2]){
                temp[i]=s[p1];
                p1++;
            }else{
                temp[i]=s[p2];
                p2++;
            }
        }
        for(i=left;i<=right;i++){ //转移
            s[i]=temp[i];
        }
    }
    
    int main(){
        freopen(" data.txt","r",stdin);
        time(NULL);
        int i;
    
        for(i=1;i<=10000;i++){
            scanf("%lf",&test[i]);
        }
        unsort(test,1,10000);
    
        printf("第1个:%lf
    ",test[1]);
        printf("第10个:%lf
    ",test[10]);
        printf("第100个:%lf
    ",test[100]);
        printf("第1000个:%lf
    ",test[1000]);
        printf("第10000个:%lf
    ",test[10000]);
    
        return 0;
    }
    View Code
  • 相关阅读:
    *Triangle
    Pascal's Triangle II
    Pascal's Triangle
    Merge Sorted Array
    House Robber
    Find Peak Element
    Container With Most Water
    *Next Permutation
    top命令VIRT,RES,SHR,DATA
    Octave简单使用
  • 原文地址:https://www.cnblogs.com/huhuuu/p/3394971.html
Copyright © 2011-2022 走看看