ACM - 数据结构丨笛卡尔树

笛卡尔树

笛卡尔树图例(该笛卡尔树遵循根节点小于叶子节点小根堆的笛卡尔树

笛卡尔树的性质

无相同元素的数列构造出的笛卡尔树具有下列性质:
1.结点一一对应于数列元素。即数列中的每个元素都对应于树中某个唯一结点,树结点也对应于数列中的某个唯一元素。
2.中序遍历(in-order traverse)笛卡尔树即可得到原数列。
3.树结构存在堆序性质,即任意树结点所对应数值大/小于其左、右子树内任意结点对应数值

代码思路

(大根堆)
对于一个没有相同元素的数组 a[n],设定一个数组stk[n]存储数组元素的下标,设定top为stk[n]数组已经存储的元素数。用来首先从a[n]选取第一个元素成为第一个节点,并将其下标存入至stk[n]中。接下来从a[n]选取下一个元素a[i],观察stk[n]数组,找到stk[k],使得a[stk[k]]<a[i]&&a[stk[k - 1]]>a[i],于是让stk[k]=i,(若不存在stk[k]对应的元素大于a[i],则让查找到的k为0,若不存在元素小于a[i],则查找到的k即为top接下来让stk[n]数组中下标大于k的元素全部失效(即失去实际意义,代码中通过top的移动完成,类似于栈)利用上述操作,可以让stk中存储的下标所对应的数组元素保持降序,所以观察stk[n]数组的那一步只要通过while语句即可以实现。

构建树的操作,即在上述中完成k的查找之后,将 a[stk[k]]的父节点设定为a[i],将a[i]设定为a[stk[k-1]]的右子节点,将a[stk[k-1]]原先的右子节点设定为a[i]的左子节点。

构造代码

int l[maxn], r[maxn], vis[maxn], stk[maxn];
int n;		//数组长度
int a[maxn];

int build() {
   //大根堆,即树结点大于左右子数节点
   int top = 0;
   for (int i = 1; i <= n; i++) l[i] = r[i] = vis[i] = 0;	//初始化l[]、r[]、vis[]
   for (int i = 1; i <= n; i++) {
   	int k = top;								//top为栈顶(可插入元素的位置)
   	while (k > 0 && a[stk[k - 1]] < a[i]) --k;	//找到 a[stk[k - 1]] > a[i],stk[]保存的是下标 
   	if (k) r[stk[k - 1]] = i;					//让a[i]成为a[stk[k - 1]]的右子树
   	if (k<top) l[i] = stk[k];					//当k<top时,说明从栈顶到栈底有元素比新的元素小,由前面while可知该元素下标为stk[k]
   												//可能有多个小于a[i]的元素,下标为stk[k]的元素最大
   	stk[k++] = i;
   	top = k;
   }
   for (int i = 1; i <= n; i++)  vis[l[i]] = vis[r[i]] = 1; 
   int ret = 0;
   for (int i = 1; i <= n; i++) { if (vis[i] == 0)  ret = i; }
   return ret;
}

代码源https://blog.csdn.net/luyehao1/article/details/81280093
备注: 在运用该代码时,数组a[n]的第一个元素不利用,即从a[1]开始存元素。

  • 3
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值