前面两篇写了十大基本排序中的六种,剩下的四种分别为堆排序,计数排序,桶排序,基数排序。该篇只显示出堆排序,因为桶排序和计数排序我还没有掌握
堆排序
父节点: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;
}