查找与排序小结

//顺序查找
//主要是为了说明引入"哨兵"的作用
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

查找与排序小结的相关文章

pandas索引的数据查找、排序和去重小结

由于Pandas的索引比较复杂,常常在使用过程中容易搞混,所以整理一份关于索引的查找.排序.去重的总结文档. import pandas as pd import numpy as np #定义DataFrame dict={'a':[1,2,3],'b':[4,5,6],'c':[7,8,9]} df=pd.DataFrame(dict,index=['one','two','three']) df .dataframe tbody tr th:only-of-type { vertical-

C++ 中对vector&lt;T*&gt; 数组的查找和排序

//--------------------------------------------------------------------------- #include <vcl.h> #pragma hdrstop #include "Unit1.h" #include <vector> #include <algorithm> using namespace std; //-----------------------------------

查找与排序02,折半查找

折半查找,也叫二分查找,当在一个数组或集合中查找某个元素时,先定位出中间位置元素,如果要查找的元素正好和该中间位置元素相等,通过一次查找,就能找到匹配元素:如果要查找的元素小于该中间位置元素,就抛弃后面一半的元素,在前面一半的元素中再定位出中间位置元素,如此反复,直到找到匹配元素:如果要查找的元素大于该中间位置元素,就抛弃前面一半的元素,在后面一半的元素中定位出中间位置元素,如此反复. 面临的第一个问题是:中间位置元素如何定位?在折半查找中规定:当元素个数是奇数,比如有3个元素,中间位置元素是索

关于查找与排序

查找和排序都是程序中经常用到的算法 查找分为:顺序查找,二分查找.哈希表查找和二叉树排序查找. 哈希表和二叉树查找的重点在于其数据结构.哈希表的主要优点是能够在O(1)的时间查找某一元素,是效率最高的查找方式.其缺点是需要额外的空间来实现哈希表. 排序分为插入排序,冒泡排序,递归排序,快速排序等.排序的这几种方法的优劣(额外空间的消耗,平均时间复杂度和最差时间复杂度).特点是重点. 快速排序 快速排序关键在于先在数组中选择一个数字,接下来吧数组中的数字分为两部分,比选择数组小的放到左边,大的放到

查找与排序05,冒泡排序

在体验了"选择排序"和"插入排序",本篇体验的是"冒泡排序",依次遍历数组中的元素,按照升序排列,如果前一个位置元素比后一个位置元素大,两者就交换位置. 自定义一个处理整型数组的类,包含添加.显示.清除及冒泡方法以及获取数组长度的属性. class MyIntArray { private int[] arr; private int upper; //最大索引 private int index; //当前索引 public MyIntArra

排序小结 sort

排序小结 排序算法是基础之基础.在这里小结一下.方便自己查阅和学习. 1.冒泡排序(BubbleSort) 思想:比较相邻的两个元素,如果前面的元素大于后面的元素,交换之. 思路:采用双层循环.外循环控制要处理多少趟.里面循环用来做元素的交换操作.注意上下界. 稳定性:稳定 时间复杂度:O(n2) void bubbleSort(int a[], int size) { int tmp; for (int i = 0; i < size; i++) { //每一趟都会把最大的元素放入最右边的位置

二叉查找(排序)树的分析与实现

二叉排序树(Binary Sort Tree)又称二叉查找树(Binary Search Tree),亦称二叉搜索树. 图from baike 二叉排序树或者是一棵空树,或者是具有下列性质的二叉树: (1)若左子树不空,则左子树上所有结点的值均小于它的根结点的值: (2)若右子树不空,则右子树上所有结点的值均大于或等于它的根结点的值: (3)左.右子树也分别为二叉排序树: (4)没有键值相等的节点. 步骤:若根结点的关键字值等于查找的关键字,成功.否则,若小于根结点的关键字值,递归查左子树.若大

查找与排序

#include <iostream> using namespace std; //二分查找算法实现 int BinarySearch(int a[],int len,int findnum) { int low = 0; int high = len - 1; while(low <= high) { int middle = (low + high)/2; if(a[middle] == findnum) { return middle; } else if(a[middle] &

查找与排序04,插入排序

在选择排序中,从第一个元素开始,依次遍历数组中的元素,找出当前遍历元素之后的最小元素,与当前遍历元素交换位置,依此类推,是一种由前往后的排序.而在插入排序中,从第二个元素开始,依次遍历数组中的元素,把当前遍历元素与之前的元素进行比较,并插入到之前的某个位置,是一种由后往前的排序. 自定义一个类,里面维护着一个int[]类型数组,通过构造函数定义数组长度并初始化,并提供了打印和插入排序的相关方法. public class MyArray { private static int[] arr; p