关于二叉树递归遍历的问题

slmax1 2015-11-02 12:20:05

void ashow(MyStruct * p)
{
if (p != nullptr)
{
ashow(p->pLeft);
ashow(p->pRight);
cout << p->Nodedata << endl;
}
}


有没有什么办法不要让这个二叉数遍历完,比如我要查找里面一个数据,查到了就终止递归?
在cout << p->Nodedata << endl;下面加上if (p->Nodedata==1) return p->Nodedata 不行,还是会把数据打印完.
...全文
274 24 打赏 收藏 转发到动态 举报
写回复
用AI写文章
24 条回复
切换为时间正序
请发表友善的回复…
发表回复
赵4老师 2015-11-04
  • 打赏
  • 举报
回复
use the C++ exception-handling mechanism:
#include <iostream>
using namespace std;
struct MyStruct {
    int Nodedata;
    MyStruct *pLeft;
    MyStruct *pRight;
} s1,s2,s3,s4,s5,s6,s7,s8;
void ashow(MyStruct * p) {
    if (p != nullptr) {
        ashow(p->pLeft);
        ashow(p->pRight);
        cout << p->Nodedata << endl;
        if (p->Nodedata == 4) {
            throw 1;//退出递归.直接返回.
        }
    }
}
int main() {
    MyStruct *pRoot;//根

    pRoot = &s1;
    s1.Nodedata = 1;
    s2.Nodedata = 2;
    s3.Nodedata = 3;
    s4.Nodedata = 4;
    s5.Nodedata = 5;
    s6.Nodedata = 6;
    s7.Nodedata = 7;
    s8.Nodedata = 8;

    s1.pLeft = &s2;
    s1.pRight = &s3;

    s2.pLeft = &s4;
    s2.pRight = &s5;

    s3.pLeft = &s6;
    s3.pRight = &s7;
    try {
        ashow(pRoot);
    } catch (int err) {
        cout<<"catch err "<<err<<endl;
    }
    cin.get();
    return 0;
}
//4
//catch err 1
//
//
toofunny 2015-11-03
  • 打赏
  • 举报
回复
把你的代码全部贴上来。
toofunny 2015-11-03
  • 打赏
  • 举报
回复
另外,你这个“条件”值得商讨。 如果是目标条件,比如查找某个数,然后返回,那就直接


static bool bContinue = true;
void ashow(MyStruct * p)
{
    if (p != NULL && bContinue)
    {
        if (p->Nodedata != 4)
        {
            //退出递归.直接返回.
            ashow(p->pLeft);
            ashow(p->pRight);
 
        }else{
			cout << p->Nodedata << endl;
            bContinue = false;
        }
    }
}
如果是个终止条件,比如遍历这棵树,直到 Nodedata == 4,那就使用我前面说的方法就行了。
toofunny 2015-11-03
  • 打赏
  • 举报
回复
如果你只想单独对4进行处理,而不管其他序列,那就使用 zhao4zhong1 的方法,直接跳走。
toofunny 2015-11-03
  • 打赏
  • 举报
回复
因为是后根遍历,所以找到的顺寻跟输出的顺序是相反的。以下程序输出 4 2 1 , 也就是找到4 就退出函数了。

static bool bContinue = true;
void ashow(MyStruct * p)
{
    if (p != NULL && bContinue)
    {
		if (p->Nodedata != 4)
        {
            //退出递归.直接返回.
			ashow(p->pLeft);
			ashow(p->pRight);

        }
        bContinue = false;
        cout << p->Nodedata << endl;
    }
}
如果你想要输出序列跟查找序列相同,应使用先根遍历: 下面代码输出1 2 4

 
static bool bContinue = true;
void ashow(MyStruct * p)
{
    if (p != NULL && bContinue)
    {
		cout << p->Nodedata << endl;

		if (p->Nodedata != 4)
        {
            //退出递归.直接返回.
			ashow(p->pLeft);
			ashow(p->pRight);

        }else{
			bContinue = false;
		}
    }
}
slmax1 2015-11-03
  • 打赏
  • 举报
回复
引用 9 楼 I_just_smile 的回复:
void ashow(MyStruct * p) {     if (p != nullptr)     {         ashow(p->pLeft);         ashow(p->pRight);         cout << p->Nodedata << endl;         if (p->Nodedata == 4)         {             exit(0);         }     } } 如果不需要其它功能,我想这样是最懒的了。
您这个好像是直接退出程序了吧.
slmax1 2015-11-03
  • 打赏
  • 举报
回复
引用 6 楼 toofunny 的回复:
或者直接判断递归。 void ashow(MyStruct * p) { if (p != nullptr) { if (p->Nodedata != 4) { ashow(p->pLeft ); ashow(p->pRight); } cout << p->Nodedata << endl; } }
打印出1,2,3,4,5,6,7
slmax1 2015-11-03
  • 打赏
  • 举报
回复
哎,经测试全都不行... 比如我的二叉数有7个点,1,2,3,4,5,6,7 我只希望递归遍历到4的时候就结束递归, 我希望打印出来的是1,2,3,4 而不是1,2.3,4,5,6,7 不知道有什么好办法没
赵4老师 2015-11-03
  • 打赏
  • 举报
回复
setjmp Saves the current state of the program. int setjmp( jmp_buf env ); Routine Required Header Compatibility setjmp <setjmp.h> ANSI, Win 95, Win NT For additional compatibility information, see Compatibility in the Introduction. Libraries LIBC.LIB Single thread static library, retail version LIBCMT.LIB Multithread static library, retail version MSVCRT.LIB Import library for MSVCRT.DLL, retail version Return Value setjmp returns 0 after saving the stack environment. If setjmp returns as a result of a longjmp call, it returns the value argument of longjmp, or if the value argument of longjmp is 0, setjmp returns 1. There is no error return. Parameter env Variable in which environment is stored Remarks The setjmp function saves a stack environment, which you can subsequently restore using longjmp. When used together, setjmp and longjmp provide a way to execute a “non-local goto.” They are typically used to pass execution control to error-handling or recovery code in a previously called routine without using the normal calling or return conventions. A call to setjmp saves the current stack environment in env. A subsequent call to longjmp restores the saved environment and returns control to the point just after the corresponding setjmp call. All variables (except register variables) accessible to the routine receiving control contain the values they had when longjmp was called. setjmp and longjmp do not support C++ object semantics. In C++ programs, use the C++ exception-handling mechanism. Example /* FPRESET.C: This program uses signal to set up a * routine for handling floating-point errors. */ #include <stdio.h> #include <signal.h> #include <setjmp.h> #include <stdlib.h> #include <float.h> #include <math.h> #include <string.h> jmp_buf mark; /* Address for long jump to jump to */ int fperr; /* Global error number */ void __cdecl fphandler( int sig, int num ); /* Prototypes */ void fpcheck( void ); void main( void ) { double n1, n2, r; int jmpret; /* Unmask all floating-point exceptions. */ _control87( 0, _MCW_EM ); /* Set up floating-point error handler. The compiler * will generate a warning because it expects * signal-handling functions to take only one argument. */ if( signal( SIGFPE, fphandler ) == SIG_ERR ) { fprintf( stderr, "Couldn't set SIGFPE\n" ); abort(); } /* Save stack environment for return in case of error. First * time through, jmpret is 0, so true conditional is executed. * If an error occurs, jmpret will be set to -1 and false * conditional will be executed. */ jmpret = setjmp( mark ); if( jmpret == 0 ) { printf( "Test for invalid operation - " ); printf( "enter two numbers: " ); scanf( "%lf %lf", &n1, &n2 ); r = n1 / n2; /* This won't be reached if error occurs. */ printf( "\n\n%4.3g / %4.3g = %4.3g\n", n1, n2, r ); r = n1 * n2; /* This won't be reached if error occurs. */ printf( "\n\n%4.3g * %4.3g = %4.3g\n", n1, n2, r ); } else fpcheck(); } /* fphandler handles SIGFPE (floating-point error) interrupt. Note * that this prototype accepts two arguments and that the * prototype for signal in the run-time library expects a signal * handler to have only one argument. * * The second argument in this signal handler allows processing of * _FPE_INVALID, _FPE_OVERFLOW, _FPE_UNDERFLOW, and * _FPE_ZERODIVIDE, all of which are Microsoft-specific symbols * that augment the information provided by SIGFPE. The compiler * will generate a warning, which is harmless and expected. */ void fphandler( int sig, int num ) { /* Set global for outside check since we don't want * to do I/O in the handler. */ fperr = num; /* Initialize floating-point package. */ _fpreset(); /* Restore calling environment and jump back to setjmp. Return * -1 so that setjmp will return false for conditional test. */ longjmp( mark, -1 ); } void fpcheck( void ) { char fpstr[30]; switch( fperr ) { case _FPE_INVALID: strcpy( fpstr, "Invalid number" ); break; case _FPE_OVERFLOW: strcpy( fpstr, "Overflow" ); break; case _FPE_UNDERFLOW: strcpy( fpstr, "Underflow" ); break; case _FPE_ZERODIVIDE: strcpy( fpstr, "Divide by zero" ); break; default: strcpy( fpstr, "Other floating point error" ); break; } printf( "Error %d: %s\n", fperr, fpstr ); } Output Test for invalid operation - enter two numbers: 5 0 Error 131: Divide by zero Process and Environment Control Routines See Also longjmp
赵4老师 2015-11-03
  • 打赏
  • 举报
回复
C++ Exception Examples Home | Overview | How Do I | FAQ The real power of C++ exception handling lies not only in its ability to deal with exceptions of varying types, but also in its ability to automatically call destructor functions during stack unwinding for all local objects constructed before the exception was thrown. The context which exists between the throw site and the catch handler is referred to as the “exception stack frame.” This frame may contain objects with destructor semantics. If an exception is thrown during execution of the guarded section or in any routine the guarded section calls (directly or indirectly), an exception object is created from the object created by the throw operand. (This implies that a copy constructor may be involved.) At this point, the compiler looks for a catch clause in a higher execution context that can handle an exception of the type thrown, or a catch handler that can handle any type of exception. The catch handlers are examined in order of their appearance following the try block. If no appropriate handler is found, the next dynamically enclosing try block is examined. This process continues until the outermost enclosing try block is examined. If a matching handler is still not found, or if an exception occurs while unwinding but before the handler gets control, the predefined run-time function terminate is called. If an exception occurs after throwing the exception but before the unwind begins, the terminate function is called. You can install a custom termination function to handle such situations. See Unhandled Exceptions for more information. The following example demonstrates C++ exception handling using classes with destructor semantics. It declares two C++ classes; one (class CTest) for defining the exception object itself, and the second (class CDtorDemo) for demonstrating the destruction of a separate frame object during stack unwinding:

#include <iostream.h>

void MyFunc( void );

class CTest
{
public:
    CTest(){};
    ~CTest(){};
    const char *ShowReason() const { return "Exception in CTest class."; }

};

class CDtorDemo
{
public:
    CDtorDemo();
    ~CDtorDemo();
};

CDtorDemo::CDtorDemo()
{
    cout << "Constructing CDtorDemo." << endl;
}

CDtorDemo::~CDtorDemo()
{
    cout << "Destructing CDtorDemo." << endl;
}

void MyFunc()
{

    CDtorDemo D;
    cout<< "In MyFunc(). Throwing CTest exception." << endl;
    throw CTest();
}

int main()
{
    cout << "In main." << endl;
    try
    {
        cout << "In try block, calling MyFunc()." << endl;
        MyFunc();
    }
    catch( CTest E )
    {
        cout << "In catch handler." << endl;
        cout << "Caught CTest exception type: ";
        cout << E.ShowReason() << endl;
    }
    catch( char *str )
    {
        cout << "Caught some other exception: " << str << endl;
    }
    cout << "Back in main. Execution resumes here." << endl;
    return 0;

}
If a matching catch handler is found, and it catches by value, its formal parameter is initialized by copying the exception object. If it catches by reference, the parameter is initialized to refer to the exception object. After the formal parameter is initialized, the process of “unwinding the stack” begins. This involves the destruction of all automatic objects that were constructed (but not yet destructed) between the beginning of the try block associated with the catch handler and the exception’s throw site. Destruction occurs in reverse order of construction. The catch handler is executed and the program resumes execution following the last handler (that is, the first statement or construct that is not a catch handler). This is the output from the preceding example: In main. In try block, calling MyFunc(). Constructing CDtorDemo. In MyFunc(). Throwing CTest exception. Destructing CDtorDemo. In catch handler. Caught CTest exception type: Exception in CTest class. Back in main. Execution resumes here. Note the declaration of the exception parameter in both catch handlers: catch( CTest E ) { // ... } catch( char *str ) { // ... } You do not need to declare this parameter; in many cases it may be sufficient to notify the handler that a particular type of exception has occurred. However, if you do not declare an exception object in the exception declaration, you will not have access to the object in the catch handler clause. For example: catch( CTest ) { // No access to a CTest exception object in this handler. } A throw expression with no operand re-throws the exception currently being handled. Such an expression should appear only in a catch handler or in a function called from within a catch handler. The re-thrown exception object is the original exception object (not a copy). For example: try { throw CSomeOtherException(); } catch(...) // Handle all exceptions { // Respond (perhaps only partially) to exception //... throw; // Pass exception to some other handler }
白衣如花 2015-11-03
  • 打赏
  • 举报
回复
int flag = 1;
void ashow(MyStruct * p)
{
    if (p != nullptr && flag)
    {
        ashow(p->pLeft);
        ashow(p->pRight);
        cout << p->Nodedata << endl;
        if (p->Nodedata == 4)
        {
            //退出递归.直接返回.
            flag = 0;
        }
    }
}
赵4老师 2015-11-03
  • 打赏
  • 举报
回复
难者不会,会者不难:
#include <iostream>
using namespace std;
#include <setjmp.h>
jmp_buf mark;
struct MyStruct {
    int Nodedata;
    MyStruct *pLeft;
    MyStruct *pRight;
} s1,s2,s3,s4,s5,s6,s7,s8;
void ashow(MyStruct * p) {
    if (p != nullptr) {
        ashow(p->pLeft);
        ashow(p->pRight);
        cout << p->Nodedata << endl;
        if (p->Nodedata == 4) {
            longjmp( mark, 1 );//退出递归.直接返回.
        }
    }
}
int main() {
    MyStruct *pRoot;//根

    pRoot = &s1;
    s1.Nodedata = 1;
    s2.Nodedata = 2;
    s3.Nodedata = 3;
    s4.Nodedata = 4;
    s5.Nodedata = 5;
    s6.Nodedata = 6;
    s7.Nodedata = 7;
    s8.Nodedata = 8;

    s1.pLeft = &s2;
    s1.pRight = &s3;

    s2.pLeft = &s4;
    s2.pRight = &s5;

    s3.pLeft = &s6;
    s3.pRight = &s7;

    int jmpret;
    jmpret = setjmp( mark );
    if (jmpret==0) ashow(pRoot);
    cin.get();
    return 0;
}
//4
//
//
slmax1 2015-11-03
  • 打赏
  • 举报
回复
引用 13 楼 toofunny 的回复:
把你的代码全部贴上来。
麻烦抽空看下.谢谢
引用 14 楼 I_just_smile 的回复:
如果你只需要达到这个目的,你把我改的换上去就可以了
您这个是直接退出程序了.
slmax1 2015-11-03
  • 打赏
  • 举报
回复

#include<iostream>
#include <string>
#include <stack>

using namespace std;

struct MyStruct
{
	int Nodedata = 0;
	MyStruct *pLeft = nullptr;
	MyStruct *pRight = nullptr;

}BTree, *pBTree;

void ashow(MyStruct * p)
{
	if (p != nullptr)
	{
		ashow(p->pLeft);
		ashow(p->pRight);
		cout << p->Nodedata << endl;
		if (p->Nodedata == 4)
		{
			//退出递归.直接返回.
		}
	}
}


int main()
{
	MyStruct *pRoot;//根

	MyStruct s1;
	MyStruct s2;
	MyStruct s3;
	MyStruct s4;
	MyStruct s5;
	MyStruct s6;
	MyStruct s7;
	MyStruct s8;
	pRoot = &s1;
	s1.Nodedata = 1;
	s2.Nodedata = 2;
	s3.Nodedata = 3;
	s4.Nodedata = 4;
	s5.Nodedata = 5;
	s6.Nodedata = 6;
	s7.Nodedata = 7;
	s8.Nodedata = 8;
	s1.pLeft = &s2;
	s1.pRight = &s3;

	s2.pLeft = &s4;
	s2.pRight = &s5;

	s3.pLeft = &s6;
	s3.pRight = &s7;

	ashow(pRoot);

	cin.get();
	return 0;
}
我这个递归是后序遍历.我本来的结果是4526731 我想要的结果是 4 后面的526731不显示.
baboon_chen 2015-11-03
  • 打赏
  • 举报
回复
如果你只需要达到这个目的,你把我改的换上去就可以了
ri_aje 2015-11-02
  • 打赏
  • 举报
回复
找到以后 throw 就行了。
baboon_chen 2015-11-02
  • 打赏
  • 举报
回复
void ashow(MyStruct * p) {     if (p != nullptr)     {         ashow(p->pLeft);         ashow(p->pRight);         cout << p->Nodedata << endl;         if (p->Nodedata == 4)         {             exit(0);         }     } } 如果不需要其它功能,我想这样是最懒的了。
baboon_chen 2015-11-02
  • 打赏
  • 举报
回复
void ashow(MyStruct * p) {     if (p != nullptr)     {         ashow(p->pLeft);         ashow(p->pRight);         cout << p->Nodedata << endl;         if (p->Nodedata == 4)         {             exit(0);         }     } }
toofunny 2015-11-02
  • 打赏
  • 举报
回复
或者直接判断递归。 void ashow(MyStruct * p) { if (p != nullptr) { if (p->Nodedata != 4) { ashow(p->pLeft ); ashow(p->pRight); } cout << p->Nodedata << endl; } }
toofunny 2015-11-02
  • 打赏
  • 举报
回复
加一个条件变量。调用前先把它初始化为true,满足后设为 false void ashow(MyStruct * p, bool bContinue) { if (p != nullptr && bContinue) { if (p->Nodedata == 4) { bContinue = false; } ashow(p->pLeft , bContinue ); ashow(p->pRight, bContinue); cout << p->Nodedata << endl; } }
加载更多回复(4)

64,654

社区成员

发帖
与我相关
我的任务
社区描述
C++ 语言相关问题讨论,技术干货分享,前沿动态等
c++ 技术论坛(原bbs)
社区管理员
  • C++ 语言社区
  • encoderlee
  • paschen
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
  1. 请不要发布与C++技术无关的贴子
  2. 请不要发布与技术无关的招聘、广告的帖子
  3. 请尽可能的描述清楚你的问题,如果涉及到代码请尽可能的格式化一下

试试用AI创作助手写篇文章吧