Legen Sie eine vorzeitige Diskussion als die Wurzel des Bösen ein
Das heißt, hier sind einige Gewohnheiten, die ich eingeführt habe, um unnötige Effizienz zu vermeiden, und in einigen Fällen meinen Code einfacher und korrekter zu machen.
Hierbei geht es nicht um allgemeine Prinzipien, sondern um einige Dinge, die beachtet werden müssen, um unnötige Ineffizienzen im Code zu vermeiden.
Kenne deinen Big-O
Dies sollte wahrscheinlich in die obige ausführliche Diskussion einbezogen werden. Es ist ziemlich normal, dass eine Schleife in einer Schleife, in der die innere Schleife eine Berechnung wiederholt, langsamer sein wird. Beispielsweise:
for (i = 0; i < strlen(str); i++) {
...
}
Wenn der String wirklich lang ist, wird dies eine horrende Zeit in Anspruch nehmen, da die Länge bei jeder Iteration der Schleife neu berechnet wird. Beachten Sie, dass GCC diesen Fall tatsächlich optimiert, weilstrlen()
als reine Funktion markiert ist.
Wenn Sie eine Million 32-Bit-Ganzzahlen sortieren, ist die Blasensortierung der falsche Weg . Im Allgemeinen kann die Sortierung in der Zeit O (n * log n) (oder besser im Fall der Radix-Sortierung) durchgeführt werden. Wenn Sie also nicht wissen, dass Ihre Daten klein sein werden, suchen Sie nach einem Algorithmus, der mindestens O (n) ist * log n).
Achten Sie auch beim Umgang mit Datenbanken auf Indizes. Wenn duSELECT * FROM people WHERE age = 20
keinen Index für Personen (Alter) haben, ist eher ein O (n) -Sequenz-Scan als ein viel schnellerer O (log n) -Index-Scan erforderlich.
Ganzzahlige arithmetische Hierarchie
Bedenken Sie beim Programmieren in C, dass einige Rechenoperationen teurer sind als andere. Für ganze Zahlen sieht die Hierarchie ungefähr so aus (am billigsten zuerst):
Zugegeben, wird der Compiler in der Regel optimize Dinge wie n / 2
zu n >> 1
automatisch , wenn Sie einen Mainstream - Computer targeting sind, aber wenn Sie ein eingebettetes Gerät Targeting sind, können Sie diesen Luxus nicht zu bekommen.
Auch % 2
und & 1
haben unterschiedliche Semantik. Division und Modul runden normalerweise gegen Null, aber die Implementierung ist definiert. Gut alt >>
und &
rundet immer in Richtung negative Unendlichkeit, was (meiner Meinung nach) viel sinnvoller ist. Zum Beispiel auf meinem Computer:
printf("%d\n", -1 % 2); // -1 (maybe)
printf("%d\n", -1 & 1); // 1
Verwenden Sie daher, was Sinn macht. Denken Sie nicht, dass Sie ein guter Junge sind, indem Sie verwenden, % 2
als Sie ursprünglich schreiben wollten& 1
.
Teure Gleitkommaoperationen
Vermeiden Sie schwere Gleitkommaoperationen wie pow()
und log()
in Code, die diese nicht wirklich benötigen, insbesondere im Umgang mit Ganzzahlen. Nehmen Sie zum Beispiel das Lesen einer Zahl:
int parseInt(const char *str)
{
const char *p;
int digits;
int number;
int position;
// Count the number of digits
for (p = str; isdigit(*p); p++)
{}
digits = p - str;
// Sum the digits, multiplying them by their respective power of 10.
number = 0;
position = digits - 1;
for (p = str; isdigit(*p); p++, position--)
number += (*p - '0') * pow(10, position);
return number;
}
Diese Verwendung von pow()
(und die dazu erforderlichen int
<-> double
Konvertierungen) ist nicht nur ziemlich teuer, sondern bietet auch die Möglichkeit eines Präzisionsverlusts (der obige Code weist übrigens keine Präzisionsprobleme auf). Deshalb zucke ich zusammen, wenn ich diese Art von Funktion in einem nicht mathematischen Kontext sehe.
Beachten Sie auch, dass der unten stehende "clevere" Algorithmus, der bei jeder Iteration mit 10 multipliziert wird, prägnanter ist als der obige Code:
int parseInt(const char *str)
{
const char *p;
int number;
number = 0;
for (p = str; isdigit(*p); p++) {
number *= 10;
number += *p - '0';
}
return number;
}