排序那些事(下)

        前面两篇写了十大基本排序中的六种,剩下的四种分别为堆排序,计数排序,桶排序,基数排序。该篇只显示出堆排序,因为桶排序和计数排序我还没有掌握

堆排序

        父节点:n/2-1  这里的n是要排列的元素个数,不是数组下标

        左孩子:2*i+1 这里的 i 就是数组下标了

        右孩子:2*i+2 这里的 i 也是数组下标

        堆排序的大致过程就是

        ①建堆,建成大顶堆还是小顶堆按需建

        ②交换,将第一个arr[0],与最后一个元素交换,然后维护堆得性质,但是这里要注意维护时总的元素要减一个。

#include<stdio.h>
void sort_heap(int arr[],int n);
void heapfy(int arr[],int n,int i);//维护堆的性质
void swap(int *pa,int *pb); 
int main(void)
{
	int buf[10]={43,14,24,75,74,21,11,81,32,23};
	sort_heap(buf,10);
	for(int k=0;k<10;k++)//显示函数 
	{
		printf("%d ",buf[k]);
	}
	return 0;
 } 
 
 void sort_heap(int arr[],int n)
 {
 	//建堆,就是维护堆的性质,建成大顶堆 
 	for(int i=n/2-1;i>=0;i--)
 	{
 		heapfy(arr,n,i); 
	 }
	 //把最后一个元素依次和第一个交换,然后在维护堆的性质
	 for(int i=n-1;i>0;i--)
	 {
	 	swap(&arr[i],&arr[0]);
	 	heapfy(arr,i,0);
	 }
	  
 }
 void heapfy(int arr[],int n,int i)
 {
 	int temp=i;
	int l_pos=2*i+1;
	int r_pos=2*i+2;
	if(l_pos<n&&arr[l_pos]>arr[temp])
		temp=l_pos;
	if(r_pos<n&&arr[r_pos]>arr[temp])
		temp=r_pos;
		
	if(temp!=i)
	{
		swap(&arr[temp],&arr[i]);
		heapfy(arr,n,temp);
	}
 }
 
 void swap(int *pa,int *pb)
 {
 	int temp=*pa;
 	*pa=*pb;
 	*pb=temp;
 }

相关例题

1.有序数组中的求和因子

题目分析,利用快速排序中双哨兵的方法,若前哨兵加后哨兵的值大于因子k,那么后哨兵就要减减,若小于前哨兵就要加加,这样循环往复,直到两个哨兵相等。

//有序数组中找和的因子 
#include<stdio.h>
void find_sum_number(int arr[],int n);
int main(void)
{
	int k;
	int buf[10]={-8,-3,-1,0,4,5,6,8,10,13};
	scanf("%d",&k);
	find_sum_number(buf,k);
	return 0;
 } 
 void find_sum_number(int arr[],int n)
 {
 	int i=0;
 	int j=9;
 	while(i<j)
	 {
	 	if((arr[i]+arr[j])==n)
	 	{
	 		printf("(%d %d)\n",arr[i],arr[j]);
	 		i++;
	 		j--;
		 }
		 //如果两个数相加大于n,那么就要减小向加的数,因为又是有序数列,j-- 
		if((arr[i]+arr[j])>n)
		{
		 	j--;
		}
		//两个数相加小于n,那么就要加大相加的数,又是有序数列,i++ 
		if((arr[i]+arr[j])<n)
		{
		 	i++;
		}
	  } 
 }

 2.需要排序的子数组,意思就是要把一个数组排成有序的,那么只需要排列其中的子数组有多少

题目分析:这个题目还是可以思考快速排序中的前后双哨兵,找出最小和最大值,最小值和前哨兵比较若相等,则这个位置就不需要排序,最大值和后哨兵比较,若相等则这个位置不需要排序。那么就会移动前后哨兵,在两哨兵之间又去寻找最小值最大值,又去和前后哨兵比较,这样循环往复。

//一个数组中需要排列的子数组,给定一个无序数组,求出需要排序的最短子数组长度
//如输入arr=[2,3,7,5,4,6],返回4,因为只有{7,5,4,6}需要排序 
//思路找最大值最小值依次比较
#include<stdio.h>
int find_min(int arr[],int begin,int end);
int find_max(int arr[],int begin,int end);
int main(void)
{
	int buf[10]={3,5,14,342,7,67,54,344,65,34};
	int max,min,i=0,j=9;
	min=find_min(buf,i,j);
	max=find_max(buf,i,j);
	while((buf[i]==min||buf[j]==max)&&i<j)
	{
		if(buf[i]==min)
		{
			i++;
			min=find_min(buf,i,j);
		}
		if(buf[j]==max)
		{
			j--;
			max=find_max(buf,i,j);
		}
	}
	if(i==j)
	{
		printf("%d",0);
	}
	else
	{
		printf("%d",j-i+1);
	}
	return 0;
 } 
 int find_min(int arr[],int begin,int end)
 {
 	int min=arr[begin];
 	while(begin<=end)
 	{
 		if(min>arr[begin])
 		{
 			min=arr[begin];
		 }
		 begin++;
	 }
	 return min;
 }
 int find_max(int arr[],int begin,int end)
 {
 	int max=arr[begin];
 	while(begin<=end)
 	{
 		if(max<arr[begin])
 		{
 			max=arr[begin];
		 }
		 begin++;
	 }
	 return max;
 }

3.前k个元素,TopK问题,输入的元素不限制,只需要维持前k个

题目分析:

法一:维持一个数组,若元素小于K直接插入,若大于K,则比较后插入,和数组中最小的元素比较。

法二:利用堆排序,构建小顶堆,若小于k直接加到数组里面,然后进行堆排序。若大于k则和小顶堆的堆顶进行比较,然后维护堆的性质

/*前k个元素
第一行输入k,
后面每一行都是用户输入的元素,不管用户输入的元素,
当用户输入-1时结束,并且打印出k个倒序元素,不足k有多少打印多少
法一; 
*/
#include<stdio.h>
void shoose_to_sort(int arr[],int n,int num,int k);//n为元素下标,num为要插入的元素 
 void insert_sort(int arr[],int n);
int main(void)
{
	int k;//动态维持的k个元素 
	scanf("%d",&k);
	int buf[k];
	int count=0;//记录当前元素数量 
	int num;
	scanf("%d",&num); 
	while(num!=-1)
	{
		//分两种
		//一是元素没有满直接插入
		//二是元素已满比较插入
		 if(count<k)
		 {
		 	//直接插入 
		 	shoose_to_sort(buf,count,num,k);
		  	count++;
		  }
		  else
		  {
		  	//选择插入 
		  	shoose_to_sort(buf,count,num,k);
		   } 
		scanf("%d",&num);
	}
	//显示函数 
	for(int i=0;i<count;i++)
	{
		printf("%d ",buf[i]);
	 } 
	return 0;
 } 
 void shoose_to_sort(int arr[],int n,int num,int k)
 {
 	if(n<k)
 	{
 		arr[n]=num;
 		//进行排列
		insert_sort(arr,n); 
	 }
	 else
	 {
	 	if(arr[n-1]<num)
	 	{
	 		arr[n-1]=num;
	 		//进行排序
			insert_sort(arr,n-1); 
		 }
	 }
 }
 void insert_sort(int arr[],int n)
 {
 	if(n>0)
 	{
 		int temp=arr[n];
		int i=n-1;
		while(i>=0&&arr[i]<temp)
		{
			arr[i+1]=arr[i];
			i--;
		}
		arr[i+1]=temp; 
	 }
  } 
//法二 
//采用小顶堆,若有一个数据来了,就和根节点比较,若被交换,就维护堆得性质
#include<stdio.h>
void build_head(int arr[],int n);//建堆
void heapfy(int arr[],int n,int i);//维护堆的性质 
int main(void)
{
	int k;
	int buf[k];
	scanf("%d",&k);
	int count=0;
	int num;
	scanf("%d",&num);
	while(num!=-1)
	{
		//判断个数,若小于k就直接放到最后,然后建堆 
		if(count<k)
		{
			buf[count]=num;
			count++;
			build_head(buf,count);
		}
		else//若已有个数等于k那么就和堆顶进行比较 
		{
			if(num>buf[0])
			{
				buf[0]=num;
				build_head(buf,count);
			}
		}
		scanf("%d",&num);
	}
	//堆排序 
	for(int i=count-1;i>0;i--)
	{
		int a=buf[i];
		buf[i]=buf[0];
		buf[0]=a;
		heapfy(buf,i,0);
	}
	//显示函数 
	for(int i=0;i<count;i++)
	{
		printf("%d ",buf[i]);
	}
	return 0;
 } 
 void build_head(int arr[],int n)
 {
 	for(int i=n/2-1;i>=0;i--)
 	{
 		heapfy(arr,n,i);
	 }
 }
 void heapfy(int arr[],int n,int i)
 {
 	int temp=i;
 	int l_son=i*2+1;
 	int r_son=i*2+2;
 	if(l_son<n&&arr[l_son]<arr[temp])
 		temp=l_son;
 	if(r_son<n&&arr[r_son]<arr[temp])
 		temp=r_son;
 		
 	if(temp!=i)
 	{
 		int a=arr[temp];
 		arr[temp]=arr[i];
 		arr[i]=a;
 		heapfy(arr,n,temp);
	 }
 }

4.统计所有员工的年龄

题目分析,员工年龄都大于1小于99,可直接使用计数排序,这样就非常块

//所有员工的年龄进行排序,输入:第一行代表要输入的员工数n,第二行输入n个数(1<age<99) 
//由于年龄小于99,用计数排序会非常块
#include<stdio.h>
void age(int arr[],int n);
int main(void)
{
	int n;
	int buf[n];
	scanf("%d",&n);
	for(int i=0;i<n;i++)
	{
		scanf("%d",&buf[i]);
	}
	age(buf,n);
	return 0;
 } 
 void age(int arr[],int n)
 {
 	int buf[100]={0};
 	for(int i=0;i<n;i++)
 	{
 		buf[arr[i]]++;
	 }
	 for(int i=0;i<100;i++)
	 {
	 	while(buf[i])
	 	{
	 		printf("%d",i);
	 		buf[i]--;
		}
	 }
 }

5.数组能排列成的最小元素

题目分析,两个元素,前后,后前的构成两个字符串进行比较,冒泡法的比法

//求数组能组成的最小数
//将他们两两相比较,到 string_swap转化成字符串,一个在前一个在后进行比较 
#include<stdio.h>
#include<string.h>
void string_swap(int arr[],int i,int j);
int main(void)
{
	int buf[3]={3,32,321};
	for(int i=0;i<2;i++)
	{
		for(int j=i+1;j<3;j++)
		{
			string_swap(buf,i,j);
		}
	}
	for(int i=0;i<3;i++)
	{
		printf("%d",buf[i]);
	}
	return 0;
 } 
 void string_swap(int arr[],int i,int j)
 {
 	char buf1[100];
 	char buf2[100];
 	sprintf(buf1,"%d%d",arr[i],arr[j]);
 	sprintf(buf2,"%d%d",arr[j],arr[i]);
 	if(strcmp(buf1,buf2))
 	{
 		int a=arr[i];
 		arr[i]=arr[j];
 		arr[j]=a;
	 }
	 return;
 }

6.数组的包含,数组str1中的全部元素是否都在str2中

题目分析:

法一:暴力解法,直接一个一个比

法二,这里只是做到优化,将数组str2进行排序,然后用二分查找,这样会块很多

//数组的包含 输入两个字符串str1,str2,判断字符串str1是否全部都在str2里面
//该题法一:暴力破解
//法二:可将str2排序然后二分查找 
#include<stdio.h>
#include<string.h> 
int baoli(char a_arr[],char b_arr[]);
int main(void)
{
	char buf1[100],buf2[100];
	scanf("%s %s",buf1,buf2);
	printf("%s\n",buf1);
	printf("%s\n",buf2);
	if(baoli(buf1,buf2))
		printf("字符串%s全部包含与%s\n",buf1,buf2);
	else
		printf("字符串%s没有全部包含与%s\n",buf1,buf2);
	return 0;
 } 
 int baoli(char a_arr[],char b_arr[])
 {
 	int log=0;
 	for(int i=0;i<strlen(a_arr);i++)
 	{
 		log=0;
 		for(int j=0;j<strlen(b_arr);j++)
 		{
 			if(a_arr[i]==b_arr[j])
 				log=1;
		}
		if(log==0)//也就是说在上面一个循环中没有与之匹配的字符 
			return 0;
	 }
	 return 1; 
 }
 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值