在公司面试时,当场写排序比较多,虽然都是老掉牙的问题,还是要好好准备下
快速排序,以第一个元素为关键词比较,每次比较结束,关键词都会去到最终位置上
//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; }
改了下,更通俗了些
#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(); }
第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\n",s[kth]); //mysort(1,n); for(i=1;i<=n;i++){ printf("%d ",s[i]); }printf("\n"); } return 0; }
改的适合自己的模板
#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(); }
根据堆的定义,堆是一个完全二叉树,手写了个大顶堆,其实堆就两个操作,入堆(需要向上调整),出堆(需要向下调整),堆排序就是依次把堆顶元素出堆
向上调整不需要选择,因为祖先只有一个;向下调整需要选择是从左子树还是右子树,因为儿子可能有两个
#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; }
//发现原来的堆排序写的有点罗嗦,改了一下
#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; }
//这个数据量可以控制
#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(); }
希尔排序是插入排序的一种变形,是步长不短缩小的插入排序
#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; }
/*插入排序与希尔排序的实例比较*/
希尔排序有时被叫做缩减增量排序(diminishing increment sort),使用一个序列h1,h2,h3……这样一个增量序列。只要h1=1时,任何增量序列都是可以的。但有些可能更好。对于希尔排序为什么会比直接插入排序快的原因,我们可以来看一个比较极端的例子: 假如对于一个数组{8,7,6,5,4,3,2,1}以从小到大的顺序来排。直接插入排序显然是很悲剧的了。 它的每次排序结果是这样的: 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
归并排序,思考将两个有序数列变成一个有序数列的过程,归并就是由小到大重复这个过程,最终使数组有序
#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; }