//顺序查找
//主要是为了说明引入"哨兵"的作用
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;
if(temp.low<low-1){
S[++top].low=temp.low;
S[top].high=low-1;
}
if(low+1<temp.high){
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
/*计数排序:对一个待排序的表(用数组表示)进行排序,并将排序结果存放到另一个新的表中。必须注意的是:
表中的所有待排序的关键码互不相同,计数排序算法针对表中的每个记录,扫描待排序的表一趟,统计表中有多少
个记录的关键码比该记录的关键码小,假设针对某一个记录,统计出的计数值为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
查找与排序小结
最新推荐文章于 2021-06-04 18:21:39 发布