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] を下方に調整する必要があります。ヒープのサイズを 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.csdn.net/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;
}

ここに画像の説明を挿入

他のアルゴリズム

線分木、木配列、トライ木(辞書木)、二分探索木、赤黒木(平衡二分探索木)など。

おすすめ

転載: blog.csdn.net/m0_46161051/article/details/113663294