I have to lament that code is indeed an art. Even if you learn more and write more, the simplest operation may be just "completed this function". How to be efficient, beautiful completion really requires some accomplishments. for example, how to calculate the average of two int types and return them? Today, I will summarize several data exchange methods that I have seen recently. I hope I can take a look at the art of the program.
Today, the task is very simple. It is the first problem for every beginner to learn C/C ++: Exchange two pieces of data.
During the strict period, we will clarify the conditions: Given two int variables A, B, the content of A, B is exchanged.
Next we will take a step-by-step approach to solve this problem.
First of all, it is a wrong practice that many beginners think.
A = B;
B =;
"Since it is a, B exchange, then it will be okay to give B to a and give a to B at the same time? "
The problem is that the computer cannot "at the same time" to complete these two statements, and the program must determine a sequence of execution. Therefore, the result of the above code execution is, B contains the content of the original B variable.
If you think it is hard to understand, take two cups. The red cup contains Sprite, and the blue cup contains cola. Now I want the red cup to contain cola, and the blue cup contains Sprite, you will not always pour cola from the blue cup into the red cup. Can you at the same time, Sprite from the red cup into the blue cup?
Maybe you will immediately think of a solution to this problem: with the help of the third cup, first pour sprite into the third cup, and then pour cola into the red cup (now empty ), finally, Sprite is poured from the third cup to the blue cup.
The same idea can be put into the program. The cup can be regarded as memory, and the content in the cup is the data in the memory. To complete the switching operation, we need to introduce the third variable, set it to C. We can get the following code from the process of refreshing drinks:
C =;
A = B;
B = C;
In this way, the task of switching two numbers can be successfully completed.
The problem is that since only two variables are required before and after data exchange, I need to introduce the third variable during the exchange, is this variable necessary? Is there a way to complete the exchange task without using new variables?
Actually, the answer seems incredible, but I noticed that there was no new number in the entire operation process based on the concept of A and B. However, the following method is used:
A = A + B;
B = A-B;
A = A-B;
The switch operation can be completed. the reason is that although we didn't introduce the third variable, we introduced the third data (a + B), so we only need, one of B's data can be determined by another. this is his cleverness. With two variables, the storage of the three variables is completed with the help of computation, so that the exchange is quite simple.
This method is novel. The key to its feasibility is +, which is a pair of reversible operations. In this case, we can also use another reversible operation to replace + ,-, for example, we can use multiplication, power, and square. however, their accuracy and speed cannot be compared with addition or subtraction.
However, there is also a magical operation that can complete the above functions-the exclusive or inverse operation is not anything else, it is just the exclusive or itself, so the above Code can be rewritten in this way
A = a ^ B;
B = a ^ B;
A = a ^ B;
At this point, the exchange problem has found a very beautiful method from the mathematical point of view. From the computer point of view, this method is the same as the first method to apply for variables (called method) how much is the difference in efficiency?
Method A compiled code is as follows (vc6)
10: c =;
0040186a mov eax, dword ptr [ebp-4]
0040186d mov dword ptr [ebp-0Ch], eax
11: A = B;
00401870 mov ECx, dword ptr [ebp-8]
00401873 mov dword ptr [ebp-4], ECx
12: B = C;
00401876 mov edX, dword ptr [ebp-0Ch]
00401879 mov dword ptr [ebp-8], EDX
There are 6 steps involved, involving six access operations.
The Code Compiled by this method is as follows:
10: A = a ^ B;
0040186a mov eax, dword ptr [ebp-4]
0040186d XOR eax, dword ptr [ebp-8]
00401870 mov dword ptr [ebp-4], eax
11: B = a ^ B;
00401873 mov ECx, dword ptr [ebp-4]
00401876 XOR ECx, dword ptr [ebp-8]
00401879 mov dword ptr [ebp-8], ECx
12: A = a ^ B;
0040187c mov edX, dword ptr [ebp-4]
0040187f XOR edX, dword ptr [ebp-8]
00401882 mov dword ptr [ebp-4], EDX
There are a total of 9 steps and 9 memory access operations. In this case, although the latter method saves one memory, the time overhead is 50% higher than the first method.
The contradiction between time and space exists forever in the program. It is extremely difficult to find a dual-Optimization Algorithm of time space ~
However, we will continue to talk about this method with low time efficiency, because it has not fully utilized the power of C/C ++.
Considering that the return value of the = operator is the content of the right operand, the preceding formula can be written as follows:
A = a ^ (B = B ^ (A = a ^ B ));
What? Looks messy? Then try again ^ = and rewrite the expression above
A ^ = B ^ = a ^ = B;
Remember, the above formula completes the exchange of A and B data, which is very symmetrical and elegant, but there is no improvement in efficiency. it's just an art of form. You can write it in your code as a show off ~~
If we are not rational enough to have a good harvest of time and space, we hope that the time will be better, and we do not need any third party, is there any way?
I am afraid that there are only so many advanced languages that I can do. To achieve the above goal, I only need to sacrifice the powerful sword of assembly language:
First of all, the method for embedding assembly in C/C ++ is
_ ASM
{
......
}
In this way, the exchange can be completed in this way.
_ ASM
{
MoV eax,
MoV EBX, B
MoV A, EBX
MoV B, eax
}
Because x86 supports a maximum of one memory access operation in a statement, the exchange between A and B requires one read and one write operation at a time. Therefore, at least four memory access operations are required, the above Code does not have any additional time and space.
But this method is not perfect!
The weakness is its stability. In this code, we use the eax and EBX registers, but we know whether the two registers have other functions in the context of your code, if you mistakenly modify the data in this operation, it will directly lead to a program error!
Therefore, in order to make the code work stably, you need to store the eax and EBX content in the memory in advance and overwrite it back afterwards, so that four more memory access operations are performed. the advantage of time disappears again ......
Okay. Now, the exchange methods for two numbers in C/C ++ have been discussed. We can get three feasible methods in total.
Method:
C =;
A = B;
B = C;
Method B:
A ^ = B ^ = a ^ = B;
Method C:
_ ASM // temporary storage operations of eax and EBX need to be supplemented
{
MoV eax,
MoV EBX, B
MoV A, EBX
MoV B, eax
}
The above methods are all feasible. Comparison by time efficiency is a> C> B, comparison by space efficiency is B = C> A. Here is an exception, that is, when the register usage can be determined, the method C that does not need to be supplemented with the eax and EBX temporary storage operations is a method with advantages in time space ~ Under what circumstances can I determine the usage of registers? The exchange operation can be written into a function separately, so as to prevent the use of additional registers (additional overhead of function call is required ).
Of course, in modern computer programming, the memory usage is very large, and four more B can be ignored completely, but the time considerations become increasingly strict. If a large number of switching operations are required, at the same time, in the program that needs to ensure stability, method A is the best choice.
I did not expect that at the end of the discussion, the simplest is the best ~