C ++ from scratch (8) -- C ++ Example 1

Source: Internet
Author: User

C ++ from scratch (8)

-- C ++ Example 1

The previous section describes some implementation methods of the function, but does not explain the syntax of the function, that is, what is the use of the function and why it is used. For this, this article and the future will be a few scattered, in the "C ++ from the beginning (12)" more detailed description. This article is just about the basic requirements of programmers-getting algorithms and getting code-some examples are provided to illustrate how to compile C ++ code from algorithms, it also describes multiple basic and important programming concepts (that is, concepts that exist independently of programming languages ).

Code obtained by Algorithms

At the beginning of the series, this series describes what programs are and describes that human programs (algorithms) cannot be compiled due to incompatibility between the world of CPU and the objective physical world) translation into CPU commands, but in order to be able to translate, it is necessary to make people think that something in the CPU world is something that is described by a human-thought algorithm. For example, the pictures displayed on the computer screen show different colors for different pixels through the display, and people think that is an image, while the computer only knows that it is a series of numbers, each number represents the color of a pixel.
In order to implement the above "let people think it is", the first step after obtaining the algorithm is to find out the resources to be operated in the algorithm. As mentioned above, any program describes how to operate resources, while C ++ can only operate on memory values, therefore, the first step for programming is to map the operations in the algorithm into memory values. Because the value of the memory unit and the continuity of the memory unit address can be expressed by the binary number, the first step is to express the operations in the algorithm in numbers.
The first step above is equivalent to mathematical modeling-expressing the problem in a mathematical language, but here it is just to express the operated resources with numbers (pay attention to the difference between numbers and numbers, A number is an operator in C ++ and has a relevant type. It is represented by a number rather than a binary number because it is calculated in binary, to enhance the semantics ). The second step is to map all operations on resources in the algorithm to idioms or functions.
When using mathematical language to express an algorithm, for example, ing the number of people who arrive at the station every 10 minutes to a random variable is the first step above. Then the random variable is subject to the Poisson distribution, that is, the second step above. The number of people waiting for a bus to arrive is the resource to be operated, and the algorithm provided is to change the resource every 10 minutes, change the value to a random value distributed by the Poisson function of the given parameter.
In C ++, the resource has been mapped to a number, and then the operation on the resource is mapped to a number. Only operators can operate on numbers in C ++, that is, all operations on resources in the algorithm are mapped into expression statements.
When the preceding steps are completed, only the execution sequence is left in the algorithm, and the execution sequence is written from top down in C ++, when the execution sequence needs to be changed through logical judgment, the preceding if and goto statements are used (however, the latter can also be implemented through the statement followed by if, this can reduce the use of goto statements, because the semantics of goto is jump rather than "so"), and you can consider whether loop statements can be used to simplify code. The third step is to display the execution process in a statement.
The reason for the previous step 2 is that it can be mapped to a function, that is, a certain operation may be complicated, but it also has a logic meaning that the corresponding operators cannot be directly found, in this case, we had to use the omnipotent function operator to repeat the preceding three steps for this operation to map the operation into multiple statements (such as if statements to display the logical information ), define these statements as a function for the function operator to represent that operation.
It doesn't matter if it is not clear above. The two examples below will explain how the above steps are implemented respectively.

Sort

Three cards are provided, and three integers are randomly written on them. There are three boxes marked as 1, 2, and 3 respectively. Three cards are randomly placed in the boxes 1, 2, and 3. Now we need to sort them so that the integers in the boxes 1, 2, and 3 are in the ascending order.
The simplest algorithm is given: the integers on the cards in the boxes 1, 2, and 3 are the numbers 1, 2, and 3 respectively. Then, the first and second numbers are compared, if the former is large, the cards in the two boxes are exchanged; then the first and third are compared. If the former is large, the cards are exchanged, so that the first number is the smallest. Then compare the second number with the third number. If the former is large, it is switched and the sorting is completed.
Step 1:The resources operated by the algorithm are cards in the box. to map the cards into numbers, pay attention to the differences between the cards in the algorithm and those before the cards. In the algorithm, the only way to distinguish different cards is the integer written on the card. Therefore, a long number is used to represent a card.
The algorithm contains three cards, so they are represented by three numbers. As mentioned above, numbers are in the memory, not in variables, but in ing addresses. Three long-type numbers are required here. The compiler can use the memory allocated automatically on the stack to record these numbers when defining variables, so we can define three variables long A1, A2, a3; to record three numbers, it is equivalent to three boxes containing three cards.
Step 2:The operation in the algorithm is to compare and exchange the integers on the card. The former is simple and can be implemented using logical operators (because the integers on the card are mapped to the numbers recorded in the variables A1, A2, and A3 ). The latter exchange cards in two boxes. You can take a card out of the box and place it on the table or somewhere else. Then, extract the cards from the other box and place them in the empty box. Finally, put the first card into the empty box. As mentioned above, "on the table or somewhere else" is used to store the cards that are taken out. In C ++, only the memory can store numbers, therefore, a temporary memory must be allocated to temporarily record the number.
Step 3:Operations and resources have been mapped. If there is an algorithm, replace it with IF, and replace it with, there is something repeated until we replace it with "while" or "do while", as shown in the preceding figure. The algorithm ing is complete, as shown below:
Void main ()
{
Long a1 = 34, a2 = 23, A3 = 12;
If (A1> A2)
{
Long temp = A1;
A1 = a2;
A2 = temp;
}
If (A1> A3)
{
Long temp = A1;
A1 = A3;
A3 = temp;
}
If (A2> A3)
{
Long temp = a2;
A2 = A3;
A3 = temp;
}
}
The preceding composite statement after each if defines a temporary variable temp to provide temporary memory for storing cards with the compiler's static memory allocation function. The element exchange above is not mapped to a function as described above, because it only has three statements and is easy to understand. If you want to define an exchange operation as a function, you should:
Void swap (long * P1, long * P2) void swap (Long & R1, long & R2)
{{
Long temp = * P1; long temp = R1;
* P1 = * P2; R1 = R2;
* P2 = temp; r2 = temp;
}}
Void main () void main ()
{{
Long a1 = 34, a2 = 23, A3 = 12; long a1 = 34, a2 = 23, A3 = 12;
If (A1> A2) if (A1> A2)
Swap (& A1, & A2); swap (a1, a2 );
If (A1> A3) if (A1> A3)
Swap (& A1, & A3); swap (A1, A3 );
If (A2> A3) if (A2> A3)
Swap (& A2, & A3); swap (A2, A3 );
}}
First look at the program on the left. The function is defined above to represent the exchange operation between given boxes. Note that the parameter type uses long *. Here the pointer indicates reference (note that the pointer can not only represent reference, but also has other semantics, ).
What is reference? Note that this does not refer to the reference variable proposed by C ++. The reference indicates a connection relationship. For example, if you have a mobile phone, the mobile phone number is a reference of "Talking To You", that is, as long as you have a mobile phone number, you can achieve "Talking To You ".
Another example is the shortcut provided by the Windows operating system, which is a reference to "perform operations on a file". It can point to a file, you can double-click the shortcut icon to "execute" the file it refers to (it may be opened by a software or directly executed ), however, if you delete this shortcut, it does not delete the file it points to, because it is only a reference to "perform operations on a file.
The name of a person is a reference to "identify someone", that is, when someone is admitted to college and says the name of that person, then everyone can know who the person is. Similarly, a variable is also a reference. It is a reference of a block of memory because it maps the address, and the memory block can be uniquely identified by the address, not just the identifier. Note that it is different from the previous name, because any operation on the memory block, as long as you know the first address of the memory block, you have to talk to someone face to face or eat, it is not enough to know his name.
Note that there can be more than one reference to something. For example, a person can have multiple names, variables can also have reference variables, and mobile phone numbers can also be more than one.
Note that the function is introduced to indicate exchange, and the box becomes a resource. Therefore, the box must be mapped to a number. The cards in the box are mapped to numbers of the long type, therefore, we can think of using a memory block that identifies a number that represents the card as the number type mapped to the box, that is, the first address of the memory block, that is, the long * type (note that it is not the address type, because the address type number does not return the address that records its memory ). Therefore, the above function parameter type is long *.
The program on the right is shown below. The parameter type changes to long &. Like the pointer, it still indicates reference, but note their differences. The latter indicates that it is an alias, that is, it is a ing, And the ing address is the address of the number recorded as the parameter, that is, when it needs to call this function, the number given as a parameter must be an address number. The so-called "number with addresses" indicates that this number was created by a programmer, not the address of the temporary memory generated by the compiler for temporary reasons, such as swap (A1 ++, A2 ); an error is reported. As I have already stated, because the address returned by a1 ++ is set internally by the compiler, it does not exist in the program logic, and swap (++ a1, a2) is correct. Swap (1 + 3, 34); still reports an error because the memory for recording the numbers returned by 1 + 3 is allocated internally by the compiler. In terms of program logic, they are not recorded by programmers using a certain block of memory, so there will be no memory.
A simple criterion is the parameter type that is called. If the parameter type is an address-type number, yes; otherwise, no.
It should also be noted that the above is a long & type, indicating that the modified variables do not allocate memory, that is, the compiler should statically set the address mapped to the parameters R1 and R2. For swap (A1, a2); it is the address of A1 and A2 respectively, but for swap (A2, A3); it is the address of A2 and A3, in this way, the address mapped to R1 and R2 cannot be set at one time, that is, the address mapped to R1 and R2 changes during the program running, and cannot be determined statically at compilation.
To meet the above requirements, the compiler will actually allocate memory on the stack, then pass the address to the function, and then write the code so that it seems that the R1 and R2 addresses are dynamically bound. This is the same as setting the parameter type as long *, that is, the above swap (Long &, long &); and swap (long *, long *); are the same, only the syntax is written differently. The internal semantics is the same, and the semantics is the same, indicating that the reference (although the pointer not only carries the reference semantics ). That is, when the function parameter type is a reference type, the memory will still be allocated to pass the parameter address, that is, equivalent to the pointer type as the parameter.

Merchant crossing the river

Three businessmen crossed the river with three servants. The tool used to cross the river was only one boat, and they could only carry two people across the river at the same time, including those boating. On any side of the river, as long as the number of servants exceeds the number of merchants, the servants will join up to kill the merchants and snatch their belongings, ask how to design the order of crossing the river so that everyone can safely cross the river.
Give the weakest but omnipotent algorithm-enumeration. The possible scheme of crossing the river by boat and boating back is a servant, a merchant or two businessmen, two servants and one merchant and one servant.
Therefore, each time you select one of the above five schemes to cross the river, and then check the number of people on both sides of the river to see if a servant will kill the merchant. If neither of them can, then select a person from the five schemes above to draw the ship back, and then check whether a servant will kill the merchant, if you do not have one, you can select one of the five schemes to cross the river again.
In addition to ensuring that businessmen are not killed, the preceding scheme also ensures that the number of people on both sides of the Taiwan Strait has never been displayed after the scheme is run (that is, crossing the river or planning back, otherwise, an infinite loop is formed and must be reasonable, that is, no negative number. If a scheme fails to be selected, return to another scheme and try again. If all solutions fail, return to the previous solution selection. If the solution is rejected for the first time and there is no available solution, the above question is not answered.
The above algorithm puts forward two basic and important concepts: layers and containers. The following describes the container.
The container is the thing to install, while the operation in C ++ is only a number, so the container is the thing to install numbers, that is, the memory. Generally, containers can load multiple items, that is, multiple numbers. This is simple. Just use the previous array concept. But if a box can hold a lot of apples, it will take up a lot of size, that is, whether it is an apple or two, the box will take up half a cubic meter of size. Array is like a box. No matter whether an element or two elements are installed, it is of the long [10] type and takes 40 bytes.
A container is used to hold things. To take out the things loaded in a container, you must have a means to identify the things loaded in the container. For an array, This is the subscript of an array, for example, long a [10]; A [3]; obtains the value of the fourth element. Because of the identifier, there is also a means to indicate which identifiers are valid. In the array above, only the first two elements record numbers, but a [3];, the result is an incorrect value, because only a [0] And a [1] Make sense.
Therefore, there are many problems with using arrays as containers, but they are very simple and can reflect the sequential relationship between elements, such as the sorted array of elements. To adapt to complex algorithms, other containers, such as linked lists, trees, and queues, must be supported. They are also called collections and are used to manage multiple elements, and each of them shows how to quickly find the elements corresponding to a given Identifier from numerous elements, it can also form a relationship between each element, such as the hierarchical relationship to be mentioned later and the sequential relationship of the previous array. For the specific implementation methods of those containers, refer to other materials, which are not listed here.
The above algorithm mentioned that "the number of people on both sides of the Taiwan Strait has never appeared". To achieve this, we need to map the resource-Number of people layout into numbers, in addition, we also need to record all the layout of people that have appeared, that is, using a container to record them. Because the structure and other concepts have not been described, we use arrays to implement this container. As mentioned above, if you select a container from an existing solution, the optional solution is also a container. The same as above, an array is still used for implementation.
Level, that is, relationship. For example, XXX in the third-year and second-class primary schools, XXX in Chengdu, Sichuan, China, all show a hierarchical relationship, this hierarchical relationship is the relationship between multiple elements. Therefore, you can find a container. The elements of the container are already hierarchical, the container represents a hierarchy. Tree containers are specifically designed for this purpose.
As mentioned in the above algorithm, "return back to the previous solution selection", that is to say, the first time I crossed the river, I chose a merchant and a servant, and then I chose a merchant's solution, at this time, if you select the two servants to cross the river, it will be wrong, then you will re-choose the cross-river solution. Assuming that all the schemes for crossing the river fail at this time, you must move back and select a new one, for example, select a servant to return. For this reason, we only need to return to the last state, that is, the layout of the number of people and the selection scheme, so we can put these in the container, each of them depends on the sequential relationship, that is, the second cross-river scheme must be considered only when the first cross-river scheme is successful. Therefore, use the array container with the sequential relationship.
Step 1:The preceding algorithm has two resources: the boat ride scheme and the number of people on both sides of the Strait. There are up to five boat hailing schemes. Here, a char-type number is used to map it. That is, the first four digits of the 8-bit binary number are interpreted in the complement code format to represent the number of servants, the last four digits represent the number of merchants. Therefore, a merchant and a servant are (1 <4) | 1. The number of people on both sides of the Taiwan Strait, that is, the number of businessmen on both sides of the Taiwan Strait and the number of servants. Since there are only 3 + 3 = 6 people in total, this can be mapped using char-type numbers, however, the number of people on both sides of the Taiwan Strait can only be mapped to one person, while the number of people on both sides of the Taiwan Strait is actually 4 (the number of businessmen and servants on both sides of the Taiwan Strait ), here we use a char [4] to implement it (it is best to use structure ing instead of char [4], as described in the next article ). For example, char a [4] indicates the number of people, a [0] indicates the number of merchants on the left side of the bank, and a [1] indicates the number of servants on the left, A [2] indicates the number of merchants on the right of the riverbank, and a [3] indicates the number of servants on the right.
Pay attention to the container mentioned above. Here, an array should be used to install an optional boat ride solution, such as char SLN [5];. In this case, you also need to record the used Boat Ride Scheme. Because the elements of the array have a sequential relationship, you do not need to regenerate a container and directly use a char number to record the mark. When this number is 3, this indicates that SLN [0], SLN [1], and sln [2] have been used and both fail. Currently, SLN [3] and sln [4] are available. Similarly, two containers are required for the layout of the number of people after the successful Boat Ride scheme is installed and the selected scheme at that time. An array is used here (the linked list should actually be used) char oldlayout [200] [4], cur [200];. Oldlayout is the container that records the successful solution. Its size is 200, indicating that the result must have been obtained within the first 200 times, otherwise, memory access violations may occur because the upper limit of the array is exceeded. Why is it possible to explain in C ++ from scratch (15th.
As mentioned above, containers such as arrays cannot determine the valid elements in them and must be determined by the outside world. In this case, an unsigned char cursln; is used to record the number of valid elements in oldlayout and cur. When cursln is 3, it indicates oldlayout [0] [0 ~ 3]. oldlayout [1] [0 ~ 3] and oldlayout [2] [0 ~ 3] are both valid. Similarly, cur [0], cur [1], and cur [2] are both valid, whereas subsequent events such as cur [3] are invalid.
Step 2:Operations include: execution of the cross-river scheme, execution of the Back Scheme, check whether the scheme is successful, return to the previous scheme selection, whether all people cross the river, and determine whether the layout of the number of people is the same. As follows:
The first two operations: subtract the current number of people on the left bank from the number set in the corresponding scheme, and add the number of people on the right bank. To display the current number of people on the left bank, use oldlayout [cursln] [0] And oldlayout [cursln] [1, the number of people in the corresponding solution is (SLN [cur [cursln] & 0xf0)> 4 and sln [cur [cursln] & 0xf. Because these two operations are very similar, but one is addition and the other is subtraction, so it is defined as a function, in order to operate variables such as oldlayout and cursln in the function, you need to define these variables as global variables.
Check successful: Check whether
Oldlayout [cursln] [1]> oldlayout [cursln] [0] & oldlayout [cursln] [0] and whether
Oldlayout [cursln] [3]> oldlayout [cursln] [2] & oldlayout [cursln] [2]
And ensure that they are not negative and there is no conflict with the original solution. Check whether it is the same as the original scheme. It is used to enumerate all the original schemes and compare it with the current scheme. Because it is complicated, it is defined as a function here and the bool type is returned to indicate whether it is in conflict.
Return to the previous solution or to the next solution. You only need to use cursln -- or cursln ++. If everyone crosses the river, only oldlayout [cursln] [0 ~ 1] oldlayout [cursln] [2 ~ 3] is 3. To determine whether the layout of the number of people is the same, you only need to determine whether the corresponding elements are equal.
Step 3:The rest of the following is nothing. Just put together the operations in the order of the algorithm, and note that "Repeat until all people cross the river" is converted into do while. As follows:
# Include <stdio. h>
// Represents a merchant, a servant, two businessmen, two servants, one merchant, and one servant respectively.
Char SLN [5] = {(1 <4), 1, (2 <4), 2, (1 <4) | 1 };
Unsigned char cursln = 1;
Char oldlayout [200] [4], cur [200];

Void dosolution (char B)
{
Unsigned long oldsln = cursln-1; // temporary variable, out of Efficiency
Oldlayout [cursln] [0] =
Oldlayout [oldsln] [0]-B * (SLN [cur [cursln] & 0xf0)> 4 );
Oldlayout [cursln] [1] =
Oldlayout [oldsln] [1]-B * (SLN [cur [cursln] & 0xf );
Oldlayout [cursln] [2] =
Oldlayout [oldsln] [2] + B * (SLN [cur [cursln] & 0xf0)> 4 );
Oldlayout [cursln] [3] =
Oldlayout [oldsln] [3] + B * (SLN [cur [cursln] & 0xf );
}
Bool berepeated (char B)
{
For (unsigned long I = 0; I <cursln; I ++)
If (oldlayout [cursln] [0] = oldlayout [I] [0] & // although the four numbers are equal
Oldlayout [cursln] [1] = oldlayout [I] [1]
Oldlayout [cursln] [2] = oldlayout [I] [2] & // is replaced by a 4-byte long number
Oldlayout [cursln] [3] = oldlayout [I] [3]
(I & 1 )? 1:-1) = B) // compare the scheme after the river crossing and the scheme after the return
// I & 1 is equivalent to I % 2, I & 7 is equivalent to I % 8, I & 63 is equivalent to I % 64
Return true;
Return false;
}
Void main ()
{
Char B = 1;
Oldlayout [0] [0] = oldlayout [0] [1] = 3;
Cur [0] = oldlayout [0] [2] = oldlayout [0] [3] = 0;
For (unsigned char I = 0; I <200; I ++) // initialize the Initialization Scheme for each selection scheme as SLN [0]
Cur [I] = 0; // because cur is a global variable, it has been assigned 0 in VC.
// The reason is related to the data section, which is not listed here
Do
{
Dosolution (B );
If (oldlayout [cursln] [1]> oldlayout [cursln] [0] & oldlayout [cursln] [0]) |
(Oldlayout [cursln] [3]> oldlayout [cursln] [2] & oldlayout [cursln] [2]) |
Oldlayout [cursln] [0] <0 | oldlayout [cursln] [1] <0 |
Oldlayout [cursln] [2] <0 | oldlayout [cursln] [3] <0 |
Berepeated (B ))
{
// Reselect the current plan
P:
Cur [cursln] ++;
If (cur [cursln]> 4)
{
B =-B;
Cur [cursln] = 0;
Cursln --;
If (! Cursln)
Break; // no answer to this question
Goto P; // re-check to ensure the effectiveness of cur [cursln]
}
Continue;
}
B =-B;
Cursln ++;
}
While (! (Oldlayout [cursln-1] [0] = 0 & oldlayout [cursln-1] [1] = 0 &&
Oldlayout [cursln-1] [2] = 3 & oldlayout [cursln-1] [3] = 3 ));

For (I = 0; I <cursln; I ++)
Printf ("% d/T % d/N ",
Oldlayout [I] [0],
Oldlayout [I] [1],
Oldlayout [I] [2],
Oldlayout [I] [3]);
}
The initialization method of the preceding array SLN [5] is described in the next section. The preceding pre-compiled command # include will be described in "C ++ from scratch (10)". You can skip it here. For usage of the printf function used above, please refer to other materials. Here it only outputs the variable value on the screen.
As mentioned above, this method is an enumeration method, which is basically a omnipotent method and relies on the computing power of the CPU. Generally, programmers will think of this algorithm as soon as possible. Its disadvantage is its extremely low efficiency. A large amount of CPU resources are wasted on unnecessary computing, which is also the cause of the bottleneck. Due to its omnipotent nature, it is easy to put thinking into it during programming. For example, if the sum is 1 to 100, it is generally written as follows:
For (unsigned long I = 1, s = 0; I <= 100; I ++) S + = I;
However, it should be noted that the unsigned long s = (1 + 100) * 100/2; should not be occupied by the omnipotent enumeration.
The preceding number of people is best mapped to a structure. ing to Char [4] does not show strong semantics and the code is less readable. The next section describes the structure and the meaning of the Type-how to explain the memory value.

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.