线段树

题目:对一个数组重复的随机的找一段连续数据进行求和(query)以及重复的随机的改(updata)某一个位置处的值

第一种解法:再开一个数组,这个数组用来存和,图如下:

void Sum_arr(int *arr,int len1, int *sum_arr)
{
    int i=0,j=0;
    while(i < len1)
    {
        if(i == 0)
	 {
	        sum_arr[i] = arr[i];
                i++;
	}
	sum_arr[i] = sum_arr[i-1] + arr[i];
	i++;
    }
}

第二种方法,就是把这个数组中的数用近似满二叉树的方式存起来

思想就是,这棵树的根存的是整个数组的和,即在存储的时候有因为数的特性我们将它们分开存储,树有左右子树,那么数组就从中间P开然后分别计算和

所以代码如下:时间复杂度O(lgn)

void build_tree(int *arr, int tree[], int node, int strat,int end)
{
	if(strat == end)
	{
		tree[node] = arr[strat];
	}
	else
	{
		int mid = (strat + end) / 2;
		int left_node = 2 * node + 1;
		int right_node = 2 * node + 2;

		build_tree(arr,tree,left_node,strat,mid);
		build_tree(arr,tree,right_node,mid+1,end);
		tree[node] = tree[left_node] + tree[right_node];
	}
}

当更新某一个结点值的时候也采用类似的方法:更新完值之后要记得改arr和tree中的值

void update_tree(int *arr,int *tree,int node, int start,int end,int idx,int val) //将下标为idx处的值改为val
{
	if(start == end)
	{
		arr[idx] = val;
		tree[node] = val;
	}
	else
	{
		int mid = (start + end) / 2;
		int left_node = 2 * node + 1;
		int right_node = 2*node + 2;
		if(idx >= start && idx <= mid)
		{
			update_tree(arr,tree,left_node,start,mid,idx,val);
		}
		else
		{
			update_tree(arr,tree,right_node,mid+1,end,idx,val);
		}
		tree[node] = tree[left_node] + tree[right_node];
	}
}

思路:根据要改变的这个位置判断是在树的左边还是右边,然后沿着这条路径一直往下走直到找到这个结点,然后更改值,最后还需要把tree和arr中的值改过来

求某一段的和代码如下:时间复杂度:O(lgn)

int query_tree(int *arr, int *tree, int node, int start, int end, int L,int R)
{
	if(R < start || L > end)
	{
		return 0;
	}
	else if(L <= start && end <= R)
	{
		return tree[node];
	}
	else if(start == end)
	{
		return tree[node];
	}
	else
	{
		int mid = (start + end) / 2;
		int left_node = 2 * node + 1;
		int right_node = 2 *node + 2;
		int sum_left = query_tree(arr,tree,left_node,start,mid,L,R);
		int sum_right = query_tree(arr,tree,right_node,mid+1,end,L,R);
		return sum_left + sum_right;
	}
}

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值