排序 第K大等问题总结

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

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

排序 第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\n",s[i]);

        }

    }



    return 0;

}
View Code

改了下,更通俗了些

排序 第K大等问题总结
#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)

排序 第K大等问题总结
//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\n",s[kth]);



        //mysort(1,n);

        for(i=1;i<=n;i++){

            printf("%d ",s[i]);

        }printf("\n");

    }



    return 0;

}
View Code

改的适合自己的模板

排序 第K大等问题总结
#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("\n");

    

    key=9;

    ok=0;

    Kth(1,n);

    

    for(i=1;i<=n;i++){

        printf("%d ",shu[i]);

    }printf("\n");

    printf("kth = %d\n",ret);

    getchar();

}
View Code

 

 

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

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

排序 第K大等问题总结
#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\n",test[1]);

    printf("第10个:%lf\n",test[10]);

    printf("第100个:%lf\n",test[100]);

    printf("第1000个:%lf\n",test[1000]);

    printf("第10000个:%lf\n",test[10000]);



    return 0;

}
View Code

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

排序 第K大等问题总结
#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\n",s[i]);

    }



    return 0;

}
View Code

 //这个数据量可以控制

排序 第K大等问题总结
#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("\n");



    headSort(n);

    

    for(i=1;i<=n;i++){

        printf("%d ",newShu[i]);

    }printf("\n");



    getchar();

}
View Code

 

 

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

排序 第K大等问题总结
#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\n",test[1]);

    printf("第10个:%lf\n",test[10]);

    printf("第100个:%lf\n",test[100]);

    printf("第1000个:%lf\n",test[1000]);

    printf("第10000个:%lf\n",test[10000]);



    return 0;

}
View Code

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

排序 第K大等问题总结
希尔排序有时被叫做缩减增量排序(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

 

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

排序 第K大等问题总结
#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\n",test[1]);

    printf("第10个:%lf\n",test[10]);

    printf("第100个:%lf\n",test[100]);

    printf("第1000个:%lf\n",test[1000]);

    printf("第10000个:%lf\n",test[10000]);



    return 0;

}
View Code

 

 

你可能感兴趣的:(排序)