编程珠玑第十一章----排序
2012-07-27 13:15 javaspring 阅读(273) 评论(0) 编辑 收藏 举报1、快速排序
原理:通过一趟排序将要排序的数据分割成独立的两部分,其中一部分的所有数据都比另外一部分的所有数据都要小,然后再按此方法对这两部分数据分别进行快速排序。
void quickSort(int *a,int s,int t) //数组首地址a,数组起始位置s(初始值为0),结束位置t(初始值为n-1) { int i=s,j=t+1,temp,x=a[s]; do { do { i++; } while (a[i]<a[s]); //找比第一个元素小的元素 do { j--; } while (a[s]<a[j]); //找比第一个元素大的元素 if (i<j) //交换,将小的值放在左边,大的值放右边 { temp=a[i]; a[i]=a[j]; a[j]=temp; } }while(i<j); //划分子区间的条件 a[s]=a[j]; //交换a[s]和a[j]的值,至此成功划分两个子区间 a[j]=x; //a[j]的位置确定下来 if(s<j-1) quickSort(a,s,j-1); //递归排序左子区间 if (j+1<t) quickSort(a,j+1,t); //递归排序右子区间 }
2、堆排序
原理:首先建立最大根堆,将根元素和根堆中最后一个元素调换,这样最后一个元素就排好序了,然后将剩余的元素更新为最大根堆,按照前面的方法,直至根堆中只剩下最后一个元素,排序完成。
void initHeap(int *data,int n) //初始化根堆 { int t; for (int i=(n-1)/2;i>=0;i--) { if (2*i+2<=n&&data[2*i+1]<data[2*i+2]) //左右子树比较,左子树存放较大值 { t=data[2*i+1]; data[2*i+1]=data[2*i+2]; data[2*i+2]=t; } if (data[i]<data[2*i+1]) //左子树与父节点比较,父节点存放较大值 { t=data[2*i+1]; data[2*i+1]=data[i]; data[i]=t; } } } void heapSort(int *data,int n) //堆排序 { if (n<=0) return; //递归终止条件 initHeap(data,n); //初始化根堆 int t=data[0]; //根与最后一个数值替换 data[0]=data[n]; data[n]=t; heapSort(data,--n); //去掉最大值,继续递归 }
3、归并排序
原理:递归将待排序数组分割成n个部分,每部分只有1个元素,然后在递归将每2个部分元素进行排序,直至最后只剩下一个完整的部分,排序完成。
template<class T> void Merge(T a[],T TR[],int low,int mid,int high) //归并排序 a[low]~a[mid] 、a[mid]~a[high] { int i = low; int j = mid + 1; int k = 0; while(i <= mid && j <= high) { if(a[i] < a[j]) TR[k++] = a[i++]; else TR[k++] = a[j++]; } while(i <= mid) TR[k++] = a[i++]; while(j <= high) TR[k++] = a[j++]; for(i = low; i <= high; i++) //将排序好的数据移回到原序列中 a[i] = TR[i - low]; } template<class T> void MSort(T a[],T temp[],int low,int high) { if (low<high) //递归终止条件 { int mid = (low + high) / 2; //进行分裂 MSort(a,temp,low,mid); //将前一半继续分裂 MSort(a,temp,mid + 1,high); //将后一半继续分裂 Merge(a,temp,low,mid,high); //进行归并排序 } }
堆排序和快速排序都是不稳定的,而归并排序则是稳定的。
4、两个排好序的链表归并
pList mergeList(pList first,pList second) { pList out,p1,p2,pLast; //out为返回链表,p1指向first,p2指向second,pLast串联起两个链表 //first链表为空 if(first->next==NULL) out=second; //second链表为空 else if (second->next==NULL) out=first; //first和second都不为空 else { p1=first->next; p2=second->next; //first链表为返回链表 if (p1->data<=p2->data) { out=first; pLast=p1; //pLast作用为串联这两个链表,指向返回链表的第一个节点 p1=p1->next; } //second链表为返回链表 else { out=second; pLast=p2; p2=p2->next; } while(p1!=NULL&&p2!=NULL) { if (p1->data<=p2->data) { pLast->next=p1; //pLast指向带返回的剩余节点 pLast=p1; p1=p1->next; } else { pLast->next=p2; pLast=p2; p2=p2->next; } } if (p1!=NULL) pLast->next=p1; if(p2!=NULL) pLast->next=p2; } return out; }
5、计数排序
计数排序算法针对待排序数组中的每个记录,扫描待排序的数组一趟,统计待排序数组中有多少个记录的值比该记录的值小。假设针对某一个记录,统计出的计数值为c,那么,这个记录在新的有序数组中的合适的存放位置即为c。
计数排序一般适用于输入数据是由一个小范围的数据构成,而且是利用空间换取了时间
//计数排序,输入数组src,输出数组dest,数组长度n,数组中最大元素k void CountSort(const int *src,int *dest,int n,int k) { //c为计数数组,首先进行初始化 int *c=new int[k+1]; for(int i=0;i<k+1;i++) c[i]=0; //统计数组src中每个元素的个数 for (i=0;i<n;i++) { c[src[i]]+=1; } //累计统计个数,即src中每个元素前面有多少个元素 for (i=1;i<k+1;i++) { c[i]+=c[i-1]; } //根据c中已知的src中每个元素前面有多少个元素,从大到小输出每个元素到dest数组 int j=0; for (i=1; i<k+1;i++) { if (c[i]!=c[i-1]) { j++; dest[j-1]=i; } } }