//顺序查找 //主要是为了说明引入"哨兵"的作用 typedef struct { //查找表的数据结构 ElemType *elem; //元素存储空间基址,建表时按实际长度分配,0号单元留空 int TableLen; //表的长度 }SSTable; int Search_Seq(SStable ST,ElemType key){ //顺序表ST中顺序查找键字为key的元素。若找到则返回该元素在表中的位置 ST.elem[0]=key; //"哨兵" for(i=ST.TableLen;ST.ele[i]!=key;--i); //从后往前找 return i; //若表中不存在关键字为key的元素,将查找到i为0时退出for循环 } //折半查找 int Binary_Search(SeqList L,ElemType key){ //在有序表L中查找关键字为key的元素,若存在则返回其位置,不存在则返回-1 int low=0,high=L.TableLen-1,mid; while(low<=high){ mid=(low+high)/2; //取中间位置 if(L.elem[mid]==key) return mid; //查找成功则返回所在位置 else if(L.elem[mid]>key) high=mid-1; //从前半部分继续查找 else low=mid+1; //从后半部分继续查找 } return -1; } //折半查找的递归算法 int BinSearchRec(SStable ST,ElemType key,int low,int high){ if(low>high) return 0; mid=(low+high)/2; if(key>ST.elem(mid) BinSearchRec(ST,key,mid+1,high); else if(key<ST.elem[mid]) BinSearchRec(ST,key,low,mid-1); else return mid; } //直接插入排序(对比下面的希尔排序) void InsertSort(ElemType A[],int n){ int i,j; for(i=2;i<=n;i++) if(A[i].key<A[i-1].key){ //防止过多不必要的操作 A[0]=A[i]; //复制为哨兵,A[0]不存放元素 for(j=i-1;A[0].key<A[j].key;--j) A[j+1]=A[j]; A[j+1]=A[0]; } } //我一般这样写: void InsertSort(ElemType A[],int n){ int i,j; ElemType temp; for(i=0;i<n;i++){ temp=A[i]; for(j=i-1;j>=0&&A[j].key>temp.key;j--) A[j+1]=A[j]; A[j+1]=temp; } } //折半插入排序 void InsertSort(ElemType A[],int n){ int i,j,low,high,mid; for(i=2;i<=n;i++){ A[0]=A[i]; low=1;high=i-1; //设置折半查找的范围 while(low<=high){ mid=(low+high)/2; if(A[mid].key>A[0].key) high=mid-1; else low=mid+1; } for(j=i-1;j>=high+1;--j) A[j+1]=A[j]; A[high+1]=A[0]; } } //希尔排序 void ShellSort(ElemType A[],int n){ //对顺序表作希尔排序,本算法和直接插入排序相比,作了以下修改: //1.前后记录位置的增量是dk,不是1 //r[0]只是暂存单元,不是哨兵,当j<0时,插入位置已到 for(dk=len/2;dk>=1;dk=dk/2) for(i=dk+1;i<=n;i++) //因为A[0]作为暂存单元,所以i初始值为dk+1 if(A[i].key<A[i-dk].key){ A[0]=A[i]; for(j=i-dk;j>0&&A[0].key<A[j].key;j-=dk) A[j+dk]=A[j]; A[j+dk]=A[0]; } } //冒泡排序 void BubbleSort(ElemType A[],int n){ for(i=0;i<n-1;i++){ flag=false; for(j=n-1;j>i;j--) //从后往前比较,小元素往前走 if(A[j-1].key>A[j].key){ swap(A[j-1],A[j]) flag=true; } if(flag==false) return ; } } //我一般这么写 void BubbleSort(ElemType A[],int n){ for(i=0;i<n-1;i++){ flag=false; for(j=0;j<n-1-i;j++) //从前往后比较,大元素往后走 if(A[j].key>A[j+1].key){ swap(A[j],A[j+1]; flag=true; } if(flag==false) return ; } } //双向冒泡排序算法:在正反两个方向交替进行扫描,即第一趟把关键字最大的元素和在序列的最后面,第二趟把关键字最小的元素主在序列的最前面。如此反复进行 void BubbleSort_DoubleDirection(ElemType A[],int n){ int low=0,high=n-1; bool flag=true; while(low<high && flag){ flag=false; for(i=low;i<high;i++) if(A[i]>A[i+1]){ swap(a[i],a[i+1]); flag=true; } high--; for(i=high;i>low;i--) if(a[i]<a[i-1]){ swap(a[i],a[i-1]); flag=true; } low++; } } //快速排序(是对冒泡排序的一种改进) void QuickSort(ElemType A[],int low,int high){ if(low<high){ int pivotpos=Partition(A,low,high); //划分 QuickSort(A,low,pivotpos-1); Quicksort(A,pivotpos+1,high); } } int Partion(ElemType A[],int low,int high){ //严版教材中的划分算法(一趟排序过程) ElemType pivot=A[low]; //将当前表中第一个元素设为枢轴值,对表进行划分 while(low<high){ while(low<high && A[high]>=pivot) --high; A[low]=A[high]; while(low<high && A[low]<=pirot) ++low; A[high]=A[low]; } A[low]=pivot; return low; } while(low<high){ //上面Partion()中第一个while可以写成如下形式: while(low<high && A[high]>=pivot) --high; while(low<high && A[low]<=pivot) ++low; if(low<high){ swap(A[low],A[high]); if(A[low]==pivot && A[high]==pivot) low++; } } //快速排序的非递归算法 #define MAX 100 typedef struct { int low; int high; } elem; void QuiceSort_Non_RC(ElemType L,int length){ elem S[MAX],temp; int top=-1; S[++top].low=0; S[top].high=length-1; while(top!=-1){ temp=S[top--]; low=temp.low; high=temp.high; pivot=L[low]; while(low<high){ while(low<high && L[high]>=pivot) high--; L[low]=L[high]; while(low<high && L[low]<=pivot) low++; L[high]=L[low]; } L[low]=pivot; S[++top].low=temp.low; S[top].high=low-1; S[++top].low=low+1; S[top].high=temp.high; } } /* 基于快排的划分操作求数组第k小元素,其思想是: 从数组L[1...n]中选择枢轴pivot(随机地或者直接取第一个)进行和快速排序一样的划分操作后,表L[1...n]被划分为L[1...m-1]和L[m+1...n],其中L(m)=pivot. 讨论m与k的大小关系: (1)当m=k时,显然pivot就是所要寻找的元素,直接返回pivot即可。 (2)当m<k时,则所要寻找的元素一定落在L[m+1...n]中,从而可以对L[m+1...n]递归地查找第k-m小的元素。 (3)当m>k时,则所要寻找的元素一定落在L[1...m-1]中,从而可以对L[1...m-1]递归地查找第k小的元素。 这个算法的时间复杂度在平均情况下可以达到O(n)。而所占空间复杂度则取决于划分的方法。 */ int kth_elem(int A[],int low,int high,int k){ int pivot=A[low]; int low_temp=low; int high_temp=high; while(low<high){ while(low<high && A[high]>=pivot) --high; A[low]=A[high]; while(low<high && A[low]<=pivot) ++low; A[high]=A[low]; } A[low]=pivot; if(low==k) return A[low]; else if(low>k) return kth_elem(A,low_temp,low-1,k); else return kth_elem(A,low+1,high_temp,k-m); } /* 荷兰国旗问题:设有一个仅由红、白、蓝三种颜色的条块组成的条块序列,请编写一个时间复杂度为O(n)的算法,使得这些条块按红、白、蓝的顺序排好,即排成荷兰国旗的图案。 算法的思想:顺序扫描线性表,将红色块交换到线性表的最前面,蓝色条块交换到线性表的最后面,为此设立三个指针,其中,j为工作指针表示当前扫描的元素,i以前的元素全部为 红色,k以后的元素全部为蓝色。根据j所指示元素的颜色,决定将其交换到序列的前部或者尾部。初始时,i=0,k=n-1,算法的实现如下: */ #define RED -1 #define WHITE 0 #define BLUE 1 typedef enum{RED,WHITE,BLUE} color; //设置枚举数组 void Flag_Arrange(color A[],int n){ int i=0,j=0,k=n-1; while(j<=k) switch(A[j]){ case RED:Swap(A[i],A[j]);i++;j++;break; case WHITE:j++;break; case BLUE:Swap(A[j],A[k]);k--; //注意:这里没有j++语句以防止交换后A[j]仍为蓝色的情况! } } /*如将元素值为正数、负数和零排序成前面都是负数,接着是0,最后是正数,也是用同样的方法。 思考:为什么case RED时不用考虑交换后A[j]仍为红色,而case BLUE却需要考虑交换后A[j]仍为蓝色? 因为初始时i,j相同,且当为case RED时,i与j同步加加,所以不可能出现i与j同时指向红色且i与j不同的情况,也即要么i与j相同且同时指向红色,要么i与j不同且i与j之间全是白的。而i与k没能保证这样的关系。 */ //简单选择排序 void SelectSort(ElemType A[],int n){ for(i=0;i<n-1;i++){ min=i; for(j=i+1;j<n;j++) if(A[j]<A[min]) min=j; if(min!=i) swap(A[i],A[min]); } } //堆排序,是一种树形选择排序方法。 void BuildMaxHeap(ElemType A[],int len){ for(int i=len/2;i>0;i--) //从i=[n/2]~1,反复调整堆 AdjustDown(A,i,len); //函数AdjustDown将元素i向下进行调整 } void AdjustDown(ElemType A[],int k,int len){ A[0]=A[k]; //A[0]暂存 for(i=2*k;i<=len;i*=2){ //沿key较大的子结点向下筛选 if(i<len && A[i]<A[i+1]) //有右孩子且右孩子比左孩子大 i++; if(A[0]>=A[i]) break; else{ A[k]=A[i]; k=i; } } A[k]=A[0]; } //堆排序算法 void HeapSort(ElemType A[],int len){ BuildMaxHeap(A,len); for(i=len;i>1;i--){ //n-1趟的交换和建堆过程 swap(A[i],A[1]); //输出堆顶元素(和堆底元素交换),是原地排序从小到大 AdjustDown(A,1,i-1); //整理,把剩余的i-1个元素整理成堆 } } /*堆也支持删除与插入的操作。由于堆顶元素或为最大值或为最小值,删除堆顶元素时,先将堆的最后一个元素与堆顶元素交换,由于此时堆的性质被破坏,需对此时的根 结点进行向下调整操作。对堆进行插入操作时,先将新结点放在堆的末端,再对这个新结点执行向上调整操作,大根堆插入时向上调整的算法如下: */ void AdjustUp(ElemType A[],int k){ //参数k为向上调整的结点,也为堆的元素个数 A[0]=A[k]; int i=k/2; while(i>0 && A[i]<A[0]){ A[k]=A[i]; k=i; i=k/2; } A[k]=A[0]; } //归并排序 ElemType *B=(ElemType *)malloc((n+1)*sizeof(ElemType()); //辅助数组 void Merge(Elemtype A[],int low,int mid,int high){ //设表A的两段A[low...mid]和A[mid+1...high]各自有序,将它们合并成一个有序表 for(int k=low;k<=high;k++) B[k]=A[k]; for(i=low,j=mid+1,k=i;i<=mid && j<=high;k++){ if(B[i]<=B[j]) A[k]=B[i++]; else A[k]=B[j++]; } while(i<=mid) A[k++]=B[i++]; while(j<=high) A[k++]=B[j++]; } //合并,合并两个有序表得到排序结果 void MergeSort(ElemType A[],int low,int high){ if(low<high){ int mid=(low+high)/2; MergeSort(A,low,mid); MergeSort(A,mid+1,high); Merge(A,low,mid,high); } } //基数排序 //看这个博客吧:http://www.cnblogs.com/Braveliu/archive/2013/01/21/2870201.html /* 原数据如下: 20 80 90 589 998 965 852 123 456 789 排序后数据如下: 20 80 90 123 456 589 789 852 965 998 */ /*计数排序:对一个待排序的表(用数组表示)进行排序,并将排序结果存放到另一个新的表中。必须注意的是: 表中的所有待排序的关键码互不相同,计数排序算法针对表中的每个记录,扫描待排序的表一趟,统计表中有多少 个记录的关键码比该记录的关键码小,假设针对某一个记录,统计出的计数值为c,那么,这个记录在新的有序表中 的合适的存放位置即为c.*/ void CountSort(RecType A[],RecType B[],int n){ int cnt; for(i=0;i<n;i++)}{ for(j=0,cnt=0;j<n;j++) if(A[j].key<A[i].key) cnt++; B[cnt]=A[i]; } } //上面的双for可以改一个,以达到“任意两个记录之间只进行一次比较”: for(i=0;i<n;i++) A[i].count=0; for(i=0;i<n;i++){ for(j=i+1;j<n;j++) if(A[i].key<A[j].key) A[j].count++; else A[i].count++; } //外部排序 //看这个博客吧:http://blog.chinaunix.net/uid-25324849-id-2182916.html
时间: 2024-11-05 13:29:19