Chatting about C ++ algorithm encapsulation: exhaustive method

Source: Internet
Author: User
Tags what interface

Abstracting algorithms independently is not fresh in C ++: STL encapsulates many efficient, robust, and flexible generic components and corresponding basic algorithms, high craftsmanship, strong applicability, and extraordinary ease for our generation. I don't plan to talk about algorithm encapsulation with industrial-level requirements such as STL, because I have recently tried Master's famous books, and the reader's level is limited. I only sniffed at the fur, and my mind is weak, feeling is booming: also want to try the taste of "encapsulation. I chose the simplest exhaustive algorithm, Extracted its skeleton, and made it into a class. Taking the actual example, I thought it was run, with a low degree of abstraction and a high loss of efficiency; however, I also consciously remember what is cute. I wrote this article to remember it. The word "chatting" is easy to name. If the word "chatting" is a technical problem, you can use the word "text" as a text symbol to chat with each other.

As we all know, the exhaustive method can be regarded as the simplest Search: it is to traverse all elements in the complete set of States that may have feasible states (feasible solutions) and determine whether the results are feasible. For example, if you want to design an exhaustive algorithm such as "Finding blue apples from a bunch of Apples", the definition is as follows:

(1) full set of statuses: a bunch of Apple

(2) Feasibility: Blue Apple

Oh, well, now we have extracted two basic concepts, so we can't wait to get started, ...... How can this problem be solved? The key to the effort-consuming is to "traverse in sequence", that is, to avoid duplication or leakage. Er, we can arrange the obedient apple in a line and put it in the "Apple array". What then, we can follow the steps of Apple 0, Apple 1, Apple 2 ,... and apple n are successfully traversed. Okay, we solved the problem of traversing apple ...... Slow, we are now designing an abstract model of an algorithm. If all the objects to be exhaustive have been put there, of course, they may be collected and queued, however, if at the beginning we do not know all the objects to be exhaustive, for example, we may need to use a computer installed in a probe ship to list all living planets other than the Earth in the universe, so our computer may be able to get information about new planet as the ship moves forward, rather than getting information about the planet of the whole universe as it stops on earth (even if possible, the memory may not support such a large amount of data-even if the universe is really limited ). Therefore, we should not require that we be able to obtain all the States in the full set of States before we perform the exhaustive operation. As a result, our "Apple array" plan will be aborted. Now let's look at our exciting planet search plan: It didn't line up all the planets, so what is the key to its success? Whether the spacecraft can "patronize" all the planets with appropriate paths. We need to strengthen this condition: every time a ship reaches a planet, it will see a direction icon on the planet, marks the location of the next planet, and assumes that such a mark ensures that the spacecraft can fly to all the planets in the universe without being missed. Ah, oh ...... Do you think this is just a whimsical idea? Oh, it doesn't matter. We don't need to search for any planet, but many other practical problems can satisfy this enhancement condition. Well, I admit that this article is about a narrow-narrow effort that satisfies this enhancement condition: it must ensure that a new state can be obtained while the state is known, in addition, this "State chain" can traverse the complete state set. We call the process of getting from the current status and transferring to the next status as "status jump" (I want to use "status transfer", hi, unfortunately, it will be confused with the term of the Dynamic Planning Algorithm ):

(3) status jump: based on the current Apple, the next Apple is obtained based on a certain "traversal algorithm". This algorithm ensures that all the apples in the Apple Stack are retained, as long as the first Apple is defined by the algorithm

Obviously, different exhaustive tasks have different Traversal Algorithms, so we have to delegate the implementation to the users who call our "exhaustive Algorithm Library. However, considering that this is indeed determined by the diversity of problems, this requirement should be reasonable.

Sorry, now we have an apple source, a target Apple, and even a scheme to traverse the apple (provided by the user). Next we have a judgment standard, which is simple:

(4) criteria: whether the current Apple is a blue Apple

Next, we can consider the specific implementation of the "the classof exhaustive algorithm. We define the class name as WalkThrough.

First of all, let us note that "status" is a very important concept: Different exhaustive problems have different states. In Apple problems, "status" is apple, it contains Apple color or more information, while in the Planet search plan, the "State" is the planet, it may contain a series of amazing information such as the volume, average density, temperature, whether there is an atmosphere, whether water is detected, and how the table is active. Therefore, different States correspond to different data types, so it is necessary to use the template to enable the WalkThrough to process them. Therefore, our initial definition is as follows:

Template

Class WalkThrough

;

Everything is difficult at the beginning, but now we have made a good start. Well, continue. Before considering the specific implementation, first fantasized about what kind of service our WalkThrough can provide to users-of course, its job is to find and return to the feasible status, therefore, it seems that there should be a member function similar to getFilter. The problem is, should getFilter () return a viable State or all feasible states if there are more than one feasible state? It is not hard to imagine that returning all feasible states is not too realistic, because: 1. sometimes users only need one or a few feasible states. In this case, it is obviously inefficient and unnecessary to expose all feasible states. 2. even, the number of feasible states in some problems is infinite. For example, if the prime number is lifted, it is impossible to return all States at this time. At the same time, considering that the user may still require more than one feasible solution, we now know that a function of getNextFilter () instead of getFilter () should be provided: when it is called for the first time, returns the first viable State from the initial state, which is traversed sequentially. Subsequent calls continue to traverse the previous call as the starting point and return the next viable State. It should be noted that if the complete State collection has been traversed, it is meaningless to call this function again obviously. Therefore, it should return a flag to indicate whether the traversal has been completed. We define this function as bool. If the call is valid, true is returned. Otherwise, false is returned if the traversal is completed. obviously, we need a private State object variable curState, which is used to store the current State value.

Should we add a State reference parameter to getNextFilter to return the feasible State of every effort to the user? This is not the case here. Imagine that a user may want to obtain 5th feasible traversal States. Then, of course, he must call getNextFilter () five times (), however, the first four times do not require the feasibility of the search. Therefore, we separate "find the next viable State" from "Get the viable State currently found" to add a new getState () member function, which returns a State object, note that the getState () operation does not affect the internal state of the WalkThrough object, so it should be declared as a const member function at the same time.

Correspondingly, we need a setState () member function to change the current state value. For example, it may be used when the initial state is set. It carries a constState & type parameter to specify the State value to be set. Because the State may be of a large type, the efficiency can be guaranteed by using reference transfer, in addition, the const restriction ensures that the function does not change the value of the referenced object itself.

At the same time, the user may need to know whether a exhaustive object has been completed. Of course, he can call getNextFilter () and check the return value. However, if the traversal is not completed, getNextFilter () in addition to the final return of true, an extra search will be performed and the current status will be changed to the next viable status. The work beyond this share may not be required by the user. Therefore, we will add a member function isOver (), which returns a bool value without a parameter. If traversal is completed, true is returned, and false is returned. correspondingly, we need a private bool variable overFlag, which is used to store the State values required by isOver.

So far, the definition of WalkThrough is as follows:

Template

Class WalkThrough

Public:

Void setState (const State & s) curState = s;

State getState () const return curState;

Bool getNextFilter ();

Bool isOver () const return overFlag;

Private:

State curState;

Bool overFlag;

;

After constructing constructor and destructor, we first consider the implementation of getNextFilter (), which plays a key role. First, getNextFileter () redirects from the current state to the next state, and then determines whether the new State is feasible. If it is feasible, stop the jump and return true. Otherwise, the jump continues, repeat the preceding steps. On the other hand, if the traversal is completed and no feasible state is found, set overFlag to false and return false.

Let's delegate the jump operation and determine whether the operation is feasible to the user: the user provides two functions, and then passes the function pointer to the WalkThrough object for getNextFileter () to call. So what interface form should these two functions use? First, let's look at the jump function. A very intuitive implementation is to pass in a State object (or its const reference) and then return the "Next" State object, but at least in the returned Time, value passing will generate a copy operation on the State object (specific compiler implementations outside the language standards such as NRV optimization are not discussed). When the State object is large, overhead is not worthwhile. We should consider passing in the reference of the State object, and then "delegate" the jump function to directly modify it -- change it to the next State. Some people may question whether this operation violates the encapsulation principle, but it is reasonable to do so even if the balance in efficiency is abandoned. A jump function is considered to be responsible for the "State Conversion" function, just like an alchemy furnace-having the right or even the obligation to do so, it is responsible for "converting State" rather than "acquiring state ". Mm ...... I think I have made too much detail in language. Well, in addition to the conversion status, the jump function should also notify the getNextFilter () that calls it in time after finding that the traversal is complete. Otherwise, the getNextFilter () with most of its powers is unknown. Therefore, our jump function interface is to accept a reference of a State and return a bool value. If the traversal is not completed, the State reference changes to its successor State after the function is executed, and the function returns true; otherwise, the State remains unchanged, and the function returns false.

The function interface that determines whether the status is feasible is well defined: it accepts a constState-type reference as the status to be judged, and returns the bool value, where true indicates that the status is feasible, false indicates that the status is not feasible.

We define the jump function and the pointer types of the judgment function as StateJumper and Matcher respectively. Since you may also use these function pointer types, we will add the definition to the public domain:

Public:

Typedef bool (* StateJumper) (State &);

Typedef bool (* M

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.