回溯算法

回溯算法

思想

        回溯算法具有解题的通用性,但是效率有待提高。

        解空间的树是逻辑上的树。不是真实存在的数据结构。

题目1 打印多少次123?

运行结果是:

        为什么会打印出8次123?
        这个数组有3个元素,下标分别是0,1,2,
我们看下图:

        我们把i的值可以理解成是数组的下标。

         我们之前学的二叉树的前序遍历,中序遍历,后序遍历,都是自己调自己2次。只是当时它是调用,是二叉树的,所以起始条件是根节点。其实就像代码中的i=0一样,逐渐从根节点往叶子节点遍历,当指针到达叶子节点的时候,叶子节点遍历完了,递归就结束了。


        i=0相当于在逻辑上是一个根节点,i+1相当于下一层,以此类推。相当于在二叉树中,由父节点走向孩子节点。当i=length的时候,相当于从根节点沿着某一个路径遍历到叶子节点上。

        当i=0的时候,我们看作二叉树的根节点,0不等于3,就执行A这一句了,i=1,1不等于3,又进来执行A了,i=2,2不等于3,又进来执行A了,i=3。相当于深度遍历。3等于3了,达到if的条件了,递归结束了,打印1,2,3,然后不进入else语句了,然后这个函数执行完了。

        递归完还要一个一个回溯。
        回溯到i=2的节点上。这个节点刚才只是执行了A这一句,现在要执行B这一句i=3了!达到if条件,打印1,2,3,然后不进入else语句了,然后这个函数执行完了 。

        递归结束,回溯到上面那个节点,它把A,B这两句都执行完了,当前这个函数执行完了,然后就回溯到A:func i=1这个节点上,执行B这一句的调用,i=2,2不等于3,然后递归,又执行A这一句,i=3,打印1,2,3,然后又回溯到父节点,执行B这一句,i=3,再次打印1,2,3。

以此类推下去。

所以,最后打印8次1,2,3。
第0层,节点个数 2^0=1
第1层,节点个数 2^1=2
第2层,节点个数2^2=4
第3层,节点个数2^3=8

自己递归调用自己2次,走出来的是二叉树。
自己递归调用自己3次,走出来的是三叉树。
以此类推。

         打印出来3^3=27个123。

问题2(打印原始序列的子集)

        我们现在想打印的是原始序列123的所有的子集。

看下图

        我们记录根节点往左走,记录为1,根节点往右走,记录为0
        也就是说,往左走是执行A这句,往右走是执行B这句。
        我们在最后打印的时候,得判断,把往左走的节点打印出来,把往右走的节点不打印出来。 

        这样就可以把子集打印出来了!

 即叶子节点的个数:2^n个

        同一层的节点代表同一个下标,同一个下标对应的是数组的同一个元素,往左走表示选择当前这个元素,往右走表示不选择当前这个元素

子集树代码实现

/*
子集树代码
*/
void func(int arr[], int i, int length, int x[])
{
	if (i == length)//递归结束的条件
	{
		for (int j = 0; j < length; ++j)
		{
			if (x[j] == 1)
			{
				cout << arr[j] << " ";   // 1 2 3
			}
		}
		cout << endl;
	}
	else
	{
		x[i] = 1;//选择i节点
		func(arr, i + 1, length, x);//遍历i的左孩子

		x[i] = 0;//不选择i节点
		func(arr, i + 1, length, x);//遍历i的右孩子
	}
}
int main()
{
	int arr[] = { 1,2,3 };// 1 2 3 12 13 23 ...
	int length = sizeof(arr) / sizeof(arr[0]);
	int x[3] = { 0 };
	func(arr, 0, length, x);
	return 0;
}

时间复杂度:叶子节点的个数

子集树求解的模板

 

        length是数组长度,也就是最后一层叶子节点的层数
也可以下面这么写

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值