四个常用且重要的数据结构

一: 二叉堆,如下:

// 向下调整的方法很简单,就是把根和“较小”儿子做比较,如果根比较大,则交换它和儿子。
// 算法好比石沉大海,因此把它称为sink(下沉)过程
void sink(int p)
{
	int child = p << 1, tmp = heap[p];
	while(child <= n){
		// 找出较小儿子
		if(child < n && heap[child+1] < heap[child]) ++child;
		if(heap[child] >= tmp) break;
			heap[p] = heap[child];
			p = child;
			child = p << 1;
	}
	// 放到合适位置
	heap[p] = tmp;
}

// 先用最后一个元素代替根元素,之后执行下沉操作
int deleteMin()
{
	int iret = heap[1];
	heap[1] = heap[n--];
	sink(1);
	
	return iret;
}

// 向上调整只需要比较结点和父亲,比向下调整更容易。
// 算法好比从海底游回水面,因此称为swim过程
void swim(int idx)
{
	int tmp = heap[idx], p = idx >> 1;
	while(p && tmp < heap[idx]){
		heap[idx] = heap[p];
		idx = p;
		p = idx >> 1;
	}
	heap[idx] = tmp;
}

// 先插入到最后,然后执行上浮过程
void insert(int x)
{
	heap[++n] = x;
	swim(n);
}

// 给n个整数,构造一个二叉堆可以一个一个插入,但是有更好的方法:
// 从下往上一层一层向下调整。由于叶子无需调整,因此只需要从[n/2] 
// 开始递减到1,时间复杂度为O(n)
void build()
{
	for(int i = n/2; i > 0; i--)
		sink(i);
}

二: 查并集,如下:

// 为了解释并查集的思想,假设:集合中的每个元素是不重合的,用p[i]表示i的父亲,
// 如果p[i] == i 说明i本身是根,而rank[k]表示根节点为k的集合的某种性质(元素数量、
// 深度等) 

void makeSet(int x)
{
	p[x] = x;
}

// 找到包含此元素的集合的根元素 ,并进行路径压缩优化
// 使今后的操作比较快 
int findSet(int x)
{
	int t = x, k;
	while(t != p[t]) t = p[t];  // find root
	while(x != t){   // path compression
		k = p[x];
		p[x] = t;
		x = k;
	}
	return t;
}


void unionSet(int x, int y)
{
	int Rx = findSet(x);
	int Ry = findSet(y);
	// 启发式合并优化 
	if(rank[Rx] > rank[Ry])
		rank[Ry] = Rx;
	else
		rank[Rx] = Ry;
}


四个常用且重要的数据结构

上一篇:mobile.changePage切换页面后的事件处理


下一篇:Linux Shell脚本编写