aha7神奇的树

堆-神奇的优先排列

建立最小堆,依次删除堆顶元素值,实现从小到大的堆排序。
堆排序的时间复杂度是0(NlogN)。
堆是一个父结点大于等于(小于等于)左右子结点的完全二叉树。

//堆排序-从小到大排序建立最小堆
#include<iostream>
#include<algorithm>
using namespace std;

int h[101];//存放堆的数组
int n;//存放堆的大小

//向下调整函数
void siftdown(int i) //传入需要向下调整的结点编号i
{
	int t, flag=0;//flag标记是否需要向下调整
	//当i结点至少有右结点且需要向下调整
	while( i*2<=n && flag==0 )
	{
		//判断i结点与左结点的关系,并用t记录较小的结点编号
		if( h[i] > h[i*2])
			t = i*2;
		else
			t = i;
		//如果i有右结点
		if( i*2+1 <= n )
		{
			if(h[t] > h[i*2+1])//如果右结点值更小,更新最小的结点编号
				t = i*2+1;
		}
		//如果最小结点编号!=i
		if( t != i)
		{
			swap(h[t],h[i]);
			i = t;
		}
		else
			flag = 1;
	}
}

//建立堆
void creat() 
{
	int i;
	//从最后一个非叶结点依次向上进行调整
	for( i=n/2; i>=1; i-- )
	{
		siftdown(i);
	 } 
}

//删除最小的元素
int deletemin()
{
	int t;
	t = h[1];//记录堆顶的元素值 
	h[1] = h[n];//将堆最后一个值赋值给堆顶元素 
	n--;//堆大小减一
	siftdown(1);//从堆顶向下调整建立最小堆
	
	return t;//返回之前记录的堆顶值 
 } 
 
int main()
{
	int num;
	scanf("%d", &num);
	
	for(int i=1; i<=num; i++)
	{
		scanf("%d", &h[i]);
	}
		
	n = num;
	
	creat();//建堆 
	
	for(int i=1; i<=num; i++)//从小到大输出堆顶值 
		printf("%d ", deletemin());
	
	return 0;
}

在这里插入图片描述
堆排序还有一种更好的方法:建立最大堆,并依次将h[1]和h[n]交换,此时h[n]就是数组中最大的元素。交换后需要将h[1]向下调整保持堆的特性。将堆的大小依次减一即n–,再将h[1]和h[n]交换,将h[1]向下调整。直到堆大小为1,此时h数组就是排好序的数。

//堆排序-从小到大排序建立最大堆
#include<iostream>
#include<algorithm>
using namespace std;

int h[101], n;

void siftdown(int i)
{
	int t, flag=0;

	while(i*2<=n && flag==0)
	{
		if( h[i] < h[i*2] )
			t = i*2;
		else
			t = i;

		if( i*2+1 <= n )
		{
			if(h[t] < h[i*2+1])
				t = i*2+1;
		}

		if(t != i)
		{
			swap(h[t], h[i]);
			i = t;
		}
		else
			flag = 1;
	}
}

void creat()
{
	for(int i=n/2; i>=1; i--)
	{
		siftdown(i);
	}
}

//堆排序
void heapsort()
{
	while( n>1 )
	{
		swap(h[1], h[n]);
		n--;
		siftdown(1);
	}
}

int main()
{
	int num;
	scanf("%d", &num);
	
	for(int i=1; i<=num; i++)
		scanf("%d", &h[i]);
	n = num;
	
	creat();
	heapsort();
	
	for(int i=1; i<=num; i++)
		printf("%d ", h[i]);
	
	return 0; 
}

在这里插入图片描述
利用堆排序求数列中第k大或第k小的数。

//求数列中第K小的数
#include<vector>
#include<queue>
#include<iostream>
using namespace std;

int finfKthSmallest(vector<int>& nums, int k)
{
	priority_queue<int, vector<int> > Q;//建立最大堆 
	//注意“vector<int>”与后边的“>”中间有一个空格,否侧程序出错。
	
	for(int i=0; i<nums.size(); i++)
	{
		if(Q.size()<k)
		{
			Q.push(nums[i]);
		}
		else if(Q.top()>nums[i])
		{
			Q.pop();
			Q.push(nums[i]);
		}
	}
	
	return Q.top();
}

int main()
{
	int n, num;
	vector<int> nums;
	cin >> n;
	
	for(int i=0; i<n; i++)
	{
		scanf("%d", &num);
		nums.push_back(num);
	}
	
	printf("%d", finfKthSmallest(nums, 3));
	
	return 0;
}

以上代码参考:https://blog.youkuaiyun.com/weixin_44208324/article/details/104483788
在这里插入图片描述

擒贼先擒王-并查集

//并查集
#include<iostream>

int f[1000]={0}, n, m, k, sum=0;
//f数组初始化 
void init()
{
	for(int i=1; i<=n; i++)
		f[i]=i;
	return ;
}
//找祖宗 
int getf(int v)
{
	if(f[v]==v)
	{
		return v;
	}
	else
	{
		f[v] = getf(f[v]);
		return f[v];
	}
}
//靠左原则 
void merge(int u, int v)
{
	int t1 = getf(f[v]);
	int t2 = getf(f[u]);
	
	if(t1 != t2)
	{
		f[t2] = t1;
	}
	return ;
}

int main()
{
	scanf("%d %d", &n, &m);
	
	init();
	
	int x, y;
	for(int i=1; i<=m; i++)
	{
		scanf("%d %d", &x, &y);
		merge(x, y);
	}
	
	for(int i=1; i<=n; i++)
	{
		if(f[i] == i)
			sum++;//独立树的个数 
	}
	
	printf("%d", sum);
	return 0;
}

在这里插入图片描述

其他算法

线段树,树状数组,Trie树(字典树),二叉搜索树,红黑树(一种平衡二叉搜索树)等。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值