【考研】排序算法

列举了12种考研排序


冒泡排序

  1. 比较相邻的元素,如果第一个比第二个大,就交换他们两个。
  2. 对每一对相邻元素作同样的工作,从第一对开始,一直到最后一对,做完后,最后的元素会是最大的元素。
  3. 针对所有的元素重复上面的步骤,除排序好的。
  4. 持续对越来越少的元素重复上述步骤,直到哪次没有任何一对数字需要比较或者是交换
    在这里插入图片描述
void bubbleSort(int a[], int n)
{
	for (int i = 0; i < n - 1; i++)
	{
		for (int j = 0; j < n - i - 1; ++j)
		{
			if (a[j] > a[j + 1])
			{
				swap(a[j], a[j + 1]);
			}
		}
	}
}

选择排序

  1. 在未排序的序列中找到最小(大)元素,存放到排序序列的起始位置。

  2. 从剩下未排序元素中继续寻找最小(大)元素,然后放到自己已排序的序列的末尾。

  3. 以此类推,直到所有元素排序完毕 在这里插入图片描述

void selectionSort(int a[], int len)
{
	int min;
	for (int i = 0; i < len - 1; i++)
	{
		min = i;
		for (int j = i + 1; j < len; j++)
		{
			if (a[j] < a[min])
			{
				min = j;
			}
		}
		swap(a[i], a[min]);
	}
}

插入排序

  1. 从第一个元素开始,该元素可以认为已经被排序。
  2. 取出下一个元素,在已经排序的元素序列中从后向前扫描。
  3. 如果该元素(已排序)大于新元素,该元素移到下一个位置。
  4. 重复步骤3,直到找到已排序的元素小于或者等于新的元素的位置。
  5. 将元素插入到对应位置。
  6. 重复2~5。
    在这里插入图片描述
void InsertSort(int a[], int n)
{
	for (int i = 1; i < n; i++)
	{
		if (a[i] < a[i - 1])
		{
			int val = a[i];
			int j = i - 1;
			a[j + 1] = a[j];
			while (j > 0 && val < a[j - 1])
			{
				a[j] = a[j - 1];
				j--;
			}
			a[j] = val;
		}
	}
}

快速排序

  1. 选第一个数为标准。
  2. 将比基准小的数据交换到前面,比基准大的交换到后面
  3. 对左边的空间和右边的空间重复,直到各区间只有一个数字
    在这里插入图片描述
void QuickSort(int a[], int left, int right)
{
	if (left >= right)
		return;
	int begin = left;
	int end = right;
	//keyi定在右边,需要从左边开始找
	int keyi = end;
	int key = a[keyi];

	while (begin < end)
	{
		//因为我们从小往大排 
		//从左边开始找 找大
		while (begin < end && a[begin] <= key)
			begin++;
		a[end] = a[begin];

		//从右边开始找 找小
		while (begin < end && a[end] >= key)
			end--;
		a[begin] = a[end];
	}
	a[end] = key;

	QuickSort(a, left, end - 1);
	QuickSort(a, end + 1, right);
}

堆排序

  1. 如果要从小到大排序,建立大堆,根节点大于左右子树。
  2. 将根结和最后一个元素交换,并且树的元素个数减1。
  3. 重复1~2,直到只剩一个元素。
    在这里插入图片描述
void HeadAdjust( ElemType A[] , int k , int len){
//函数HeadAdjust将元素K为根的子树继续调整
	A[0] = A[k];		//A[0]暂存子树的根节点 
	for(i = 2*k ; i <= len ; i*=2){	//沿key较大的子节点向下筛选 
		if( i < len && A[i] < A[i+1])	
			i++;		//取key较大的子节点的下标 
		if(A[0] >= A[i])
			break;		//筛选结束 
		else{
			A[k] = A[i];	//将A[i]调整到双亲结点 
			k = i;			//修改k值,以便继续向下筛选 
		}
	} 
	A[k] = A[0];		//被筛选节点的值放入最终位置 
} 

void BuildMaxHeap( ElemType A[] , int len){
	for(int i = len/2 ; i>0 ; i-- )
		HeadAdjust(A ,i , len);	//从i = [n/2],反复调整堆 
} 

void HeapSort( ELemType A[] , int len){
//排序算法
	BuildMaxHeap(A , len);	//建立堆 
	for( i = len/2 ; i >0 ;i--){	//n-1趟的交换和键堆过程 
		Swap(A[i] , A[1]);		//输出栈顶元素(和栈底交换) 
		HeadAdjust(A , 1 , i-1);	//调整,把剩余的i-1个元素调整成堆 
	} 
}

计数排序

  1. 找出待排序的数组最大和最小的元素
  2. 统计数组中每个值为i的元素出现的个数,存入数组c的第i-min项
  3. 将下标+min的值根据在数组c中的个数存到原数组中。
    在这里插入图片描述
void CountSort(int a[], int len)
{
	int max = a[0];
	int min = a[0];
	for (int i = 0; i < len; i++)
	{
		if (a[i] > max)
			max = a[i];
		if (a[i] < min)
			min = a[i];
	}
	int l = max - min;//计算数组最大最小值的差
	int* count_a = new int[l + 1];
	for (int i = 0; i < l + 1; i++)
	{
		count_a[i] = 0;
	}

	for (int i = 0; i < len; i++)
	{
		count_a[a[i] - min]++;//统计元素个数
	}

	int j = 0;
	for (int i = 0; i < len; i)
	{
		while (j <= l && count_a[j])
		{
			count_a[j]--;
			a[i] = j + min;
			i++;
		}
		j++;
	}
}

桶排序

  1. 设置一个定量的数组当作空桶;
  2. 遍历输入数据,并且把数据一个一个放到对应的桶里去;
  3. 对每个不是空的桶进行排序;
  4. 从不是空的桶里把排好序的数据拼接起来。
    在这里插入图片描述

基数排序

  1. 取得数组中的最大数,并取得位数。
  2. arr为原始数组,从最低位开始取每个位组成radix数组。
  3. 对radix进行计数排序(利用计数排序适用于小范围数的特点)。
    在这里插入图片描述

希尔排序

  1. 选择一个增量序列t1,t2,…,tk,其中ti>tj,tk = 1。
  2. 按照增量序列个数k,对序列进行k趟排序
  3. 每趟排序根据对应的增量ti,将待排序的序列分割成若干长度为m的子序列,分别对各子表进行直接插入排序。
    在这里插入图片描述
void ShellSort(int* a, int n)
{
	printf("原数组->", gap);
	PrintArray(a, n);

	int gap = n;//间隔
	while (gap > 1)
	{
		gap = gap / 3 + 1;//保证最后一趟一定为1
		for (int i = 0; i < n - gap; i++)
		{
			int end = 0;
			int tmp = a[end + gap];
			while (end >= 0)
			{
				if (tmp < a[end])
				{
					a[end + gap] = a[end];
					end -= gap;
				}
				else
				{
					break;
				}
			}

			a[end + gap] = tmp;
		}
		printf("gap:%d->", gap);
		PrintArray(a, n);
	}
}

归并排序

  1. 把长度为n的输入序列分成两个长度为n/2的子序列;
  2. 对这两个子序列分别采用归并排序;
  3. 将两个排序好的子序列合并成一个最终的排序序列。
    在这里插入图片描述
ElemType *B=(ElemType *)malloc((n+1)*sizeof(ElemType)); //辅助数组B(动态分配内存)
 
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];
    //将A中所有元素复制到B中
	for(int i=low,j=mid+1,k=i;i<=mid&&j<=high;k++){  
//k是归并之后数组的下标计数器
		if(B[i]<=B[j])		//比较B的左右两段中的元素
			A[k]=B[i++];	//将较小值复制到A中
		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);//归并
	}
}

折半插入排序

void InsertSort(ElemType A[] , int n){
	int i , j ,high , mid , low;
	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] > A[0])
				high = mid-1;
			else
				low = mid+1;
		}
		for( j = i-1 ; i>= high+1 ; --J)
			A[j+1] = A[j];
		A[high+1] = A[0];
	}
	
}

简单排序

//顺序表形式
void SelectSort( ElemType A[] , int n ){
	for( int i = 0 ; i < n ; i++){
		min = i;		//记录最小元素位置
		for( j = i+1 ; j < n ; j++){	//从A[]里面找最小元素 
			if( A[j] < A[min])
				min = j;	//更新最小元素位置 
		} 
		if(min = !i )	
			Swap( A[i] , A[min]);		//封装的swap函数一次移动3次元素 
	}
}

//链表结构
void selectSort_LinkList(LinkList &L){
	Lnode *h = L , *p, *q , *s , *r;
 	while( p != NULL){
	 	p = s = h ;		//指针S和R记忆最大节点和其前驱,p为工作结点,q为前驱 
	 	q = r= NULL;
	 	while( p != NULL){
	 		if( p->data > s->data){
		 		s = p;
		 		r = q;		//找到更大的,记忆他和它的前驱 
		 	}
		 	q = p;
		 	p = p->nexr;	//继续寻找 
	 	}
	 	if( s == h)
	 		h = h->next;	//最大节点在原链表前端
		else
			r->next = s->next;
		s->next = L;		//最大节点在原链表表内 
		L = s;		//结点s插入结果链前端  	
	 }
} 

算法


双向冒泡排序

从正反两个方向交替扫描

void BubbleSort(int A[] , int n){
//双向冒泡排序,交替进行正反两个方向的起泡过程 
	int low = 0 , hight = n-1;
	int temp = 0 ;
	int flag = true;	//标记一趟的元素是否有被交换 
	while( low < hight && flag){	
		flag = false;
		for( int i = low ; i < n ; i++){
			if(A[i] > A[i+1]){		//从前面向后面冒泡 
				temp = A[i+1];		//发生逆序 
				A[i+1] = A[i];
				A[i] = temp;
				flag = true;
			}	
		}
		hight--;			//更新上界 
		for( int j = hight ; j < n ; j--){
			if(A[j] < A[j-1]){		//发生逆序 
				temp = A[j-1];
				A[j-1] = A[j];		
				A[j] = temp;		//交换	 
				flag = true;		//置flag 
			}
		}
		low++;			//修改下界 
	}
} 

奇数交换到偶数前面

表A基本有序,且顺序存储,每个元素都是不相同的整形元素

void Move(int A[] , int n){
//对基本有序的表A的奇偶数进行一次划分 
	int i = 0 , j = n -1 , temp = 0;	//i表示左端偶数元素下标,j表示右端奇数元素下标 
	while( i < j){
		while( i<j && A[i] % 2 != 0)	//找到偶数函数 
			i++;	
		while( i < j && A[j] %2 != 1)	//找到奇数函数 
			j--;
		if( i < j ){		//交换元素 
			temp = A[i];
			A[i] = A[j];
			A[j] = temp;
		}
		i++;
		j--;
	}	
}

随机枢纽值的快排算法:将第k个数放在它正确的位置

设有{k1,k2,k3,…,kn},现将kn放在他正确的位置上,且比较次数要求少于n的
思想:以kn为枢纽,对其进行一趟快速排序

int Partition_random(int A[] , int n ,int low , int high){
	int rand_Index = low + rand()%(high - low+1);	//求出随机值 
	swap(A[rand_Index] , A[low]);		//将枢纽值交换到第一个元素 
	int pivot = A[low];			//将第一个值设为枢纽值 
	int i = low;	//使得表A[low ...i]中的所有元素都小于pivot,初始为空表 
	for( int j = low +1 ; j <= high ; j++){	//从第二个元素开始寻找小于基准的元素 
		if(A[j] < pivot)		//找到后,交换到前面 
			swap(pivot , A[j]); 
	}
	swap(A[i] , A[low]);	//将基准元素插入最终位置 
	return i;		//返回基准元素位置 
}

寻找第k个值

void kth_Elem( int A[] , int low , int high , int k){
	int temp_low = low;
	int temp_high = high;
	int pivot = A[low];
	while(low < high){
		while( low < high && A[high] <= pivot)
			A[low] = A[high];
		high--;
		while( low < high && A[low] >= pivot )
			A[high] = A[low];
		low++;
	}
	a[low] = pivot;
	//以上就是快速排序的 部分
	if( k == low)
		return low;
	if(low >k)		//往后递归查找 
		return kth_Elem(A , temp_low , low-1 , k) ;
	else
		return kth_Elem(A , low+1 , temp_high , k);
}

两集合元素个数差最小值和元素和之差最小值

两个不相交的子集A1和A2,他们之间的元素差是| n1 - n2|,元素和之差是|S1 - S2|

int setPartition( int A[] , int n){
	int flag = 1,low = 0, low0 = 0 , high = n-1 , high0 = n-1 , k = n/2;
	int pivotkey;
	int s1 = 0 , s2 = 0;
	while(flag){
		pivotkey = A[0];		//选择衢枢轴 
		while( low < high ){	//基于枢轴进行划分 
			while( low < high && A[high] >= pivotkey )
				high --;
			if( high != low)
				A[low] = A[high];
			while( low < high && A[low] <= pivotkey)
				low ++;
			if( high != low)
				A[high] = A[low]; 
		}
		A[low] = pivotkey;
		if( low == key)	 //分组完成,算法结束 
			flag = 0;
		if( low > key){		//枢轴及之后的元素属于A2,继续对i之前的元素继续划分 
			low0 = ++low;
			high = high0;
		}
		else{			//枢轴及之前的元素属于A1
			high0 = --high;
			low = low0;
		}
	}
	for(1 = 0 ; 1 < key ; 1++){
		s1 += A[i];		
	}
	for( i = k ; i < n ; k++){
		s2 += A[i];
	}
	return s2 - s1;
}

荷兰国旗问题

仅有红、白、绿三种颜色组成的色块,编写复杂度为o(n)的算法,使其有序排列成荷兰国旗

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++; break;
		case WHITE : j++ ; break;
		case BLUE : swap(a[j] , a[k]); k--;
		//蓝色,则和k交换
		//这里没有j++语句以防止交换后a[j]仍然是蓝色的情况 
	}
}

判断数据序列是否构成小根堆

bool IsMinHeap( ElemType A[] , int len){
	if(len%2 == 0){	//若是偶数,则有一个单分支节点 
		if( A[len/2] > A[len])		//判断单分支结点 
			return false;
		for( i = len/2 - 1 ;i >=1 ; i--){
			if( A[i] > A[2*i] || A[i] > A[2*i+1])
				return false;		//判断所有双分支节点 
		}
	}
	else{	//len是奇数,
		for( i =len/2 ; i>= 1 ; i--){	//判断所有双分支节点 
			if( A[i] > A[2*i] || A[i] > A[2*i+1])
				return false;			
		}
		return true;
	}
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值