查找和排序摘要

//顺序搜索
//主要讲解介绍"哨兵"任务
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;								//若表中不存在keyword为key的元素,将查找到i为0时退出for循环
}
//折半查找
int Binary_Search(SeqList L,ElemType key){	//在有序表L中查找keyword为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 ;
	}
}
//双向冒泡排序算法:在正反两个方向交替进行扫描。即第一趟把keyword最大的元素和在序列的最后面,第二趟把keyword最小的元素主在序列的最前面。如此重复进行
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 /*计数排序:对一个待排序的表(用数组表示)进行排序。并将排序结果存放到还有一个新的表中。

必须注意的是: 表中的所有待排序的关键码互不同样。计数排序算法针对表中的每一个记录。扫描待排序的表一趟,统计表中有多少 个记录的关键码比该记录的关键码小。如果针对某一个记录。统计出的计数值为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


版权声明:本文博主原创文章,博客,未经同意不得转载。

原文地址:https://www.cnblogs.com/blfshiye/p/4826356.html