数据结构实现

1 并查集(Union/Find)

1.1 并查集(C语言)

①并查集是树的应用
②合并的过程就是“认爹”,要遵守“靠左”原则和“擒贼先擒王”原则
③在每次判断两个结点是否已经在同一棵树中的时候(一棵树就是一个集合),也必须要求其根源,必须找到树的根节点,并判断两个结点的祖宗是否是同一个根节点才行

#include<stdio.h>
int f[1001] = { 0 }, n, m, sum = 0; 

//这里是初始化,非常重要,数组里面存的是自己数组下标的编号
void init()
{
	int i;
	for (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 v, int u)
{
	int t1, t2; //t1,t2分别为v和u的祖先
	t1 = getf(v);
	t2 = getf(u);
	if (t1 != t2) //判断两个结点是否在同一个集合中,即是否为同一个祖先
	{
		f[t2] = t1; //“靠左”原则,左边变成右边的boss(上级)。即把右边的集合,作为左边集合的子集合
	}
	return;
}

int main()
{
	int i, x, y;
	scanf("%d %d", &n, &m);

	init();
	for (i = 1; i <= m; i++)
	{
		//开始合并
		scanf("%d %d", &x, &y);
		merge(x,y);
	}
	
//最后扫描有多少独立的集合
	for (i = 1; i <= n; i++)
	{
		if (f[i] == i)
			sum++;
	}
	printf("%d\n", sum);
	
	getchar();
	getchar();
	return 0;
}

2 优先队列(Priority Queue)

支持插入元素和寻找最大(小)值元素的数据结构被称为优先队列

1.1 堆(C语言)

①堆是树在优先队列中的应用
②本例为最大堆排序,最小堆详见排序算法
③若求一个数列中第K大(/小)的数,只需建立一个大小为K的最大(/小)堆,堆顶就是第K大(/小)的数。e.g.n个数取第k大。第一步:任取k数建最小堆。第二部:从k+1个数开始,与堆顶的树比较,小于堆顶的不要,大于堆顶的舍弃当前堆顶并将新数作为新堆顶,siftdown维护堆。第三部:同样方法处理第k+2~n个数。

#include<stdio.h>
int h[101]; //用来存放堆的数组
int n; //用来存储堆中元素的个数,也就是堆的大小

//交换函数,用来交换堆中的两个元素的值
void swap(int x,int y)
{
	int t;
	t = h[x];
	h[x] = h[y];
	h[y] = t;
	return;
}

//向下调整函数
void siftdown(int i) //传入一个需要向下调整的节点编号i,这里传入1,即从对的顶点开始向下调整
{
	int t, flag = 0; //flag用来标记是否需要继续向下调整
	//当i结点有儿子(其实是至少有左儿子)并且有需要继续调整的时候循环就执行
	while (i * 2 <= n && flag == 0)
	{
		//首先判断它和左儿子的关系,并用t纪录值较大的结点编号
		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(t, i); //交换它们,注意swap函数需要自己来写
			i = t; //更新i为刚才与它交换的儿子结点的编号,便于接下来继续向下调整
		}
		else
			flag = 1; //否则说明当前的父结点已经比两个子结点都要大了,不需要再进行调整了
	}
	return;
}

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

//#################变化处#################### 
//堆排序 
void heapsort() //每次把最大的放数组最后 
{
	while(n > 1)
	{
		swap(1,n);
		n--;
		siftdown(1);
	}
	return;
}

int main()
{
	int i, num;
	//读入要排序的数字的个数
	scanf("%d", &num);

	for (i = 1; i <= num; i++)
		scanf("%d", &h[i]);
	n = num;

	//建堆
	creat();
	
	//堆排序
	heapsort(); 

	//输出
	for (i = 1; i <= num; i++)
		printf("%d ", h[i]);

	getchar();
	getchar();
	return 0;
}
内含资源如下: 1.基本数据结构 1.1.Array ........... 动态数组 1.2.LinkedList ... 链表 1.3.BST .............. 二分搜索树 1.4.MapBST ..... 二分搜索树(用于实现映射) 1.5.AVLTree ...... AVL树 2.接口 2.1.Queue ........... 队列接口 2.2.Stack .............. 栈接口 2.3.Set .................. 集合接口 2.4.Map ............... 映射接口 2.5.Merger .......... 自定义函数接口 2.6.UnionFind ..... 并查集接口 3.高级数据结构 3.1.ArrayQueue .......................... 队列_基于动态数组实现 3.2.LinkedListQueue .................. 队列__基于链表实现 3.3.LoopQueue ........................... 循环队列_基于动态数组实现 3.4.PriorityQueue ....................... 优先队列_基于最大二叉堆实现 3.5.ArrayPriorityQueue ............. 优先队列_基于动态数组实现 3.6.LinkedListPriorityQueue ..... 优先队列_基于链表实现 3.7.ArrayStack ............................. 栈_基于动态数组实现 3.8.LinkedListStack ..................... 栈_基于链表实现 3.9.BSTSet ..................................... 集合_基于二分搜索树实现 3.10.LinkedListSet ....................... 集合_基于链表实现 3.11.BSTMap ................................ 映射_基于二分搜索树实现 3.12.AVLTreeMap ....................... 映射_ 基于AVL树实现 3.13.LinkedListMap .................... 映射_基于链表实现 3.14.MaxHeap ............................. 最大二叉堆 3.15.SegmentTree ...................... 线段树 3.16.Trie ......................................... 字典树 3.17.QuickFind ............................ 并查集_基于数组实现 3.18.QuickUnion ......................... 并查集_基于树思想实现
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值