Im Singleton-Modus von Java Implementation von gestern führte unser Doppel-Check-Sperrmechanismus das volatile Schlüsselwort aufgrund des Anweisungsreproblems ein. Viele Freunde fragten mich, warum ich das volatile Schlüsselwort hinzufügen muss. Und welchen magischen Effekt hat es?
In Bezug auf das volatile Schlüsselwort haben wir in der Erklärung von gestern kurz erwähnt: Shared Variablen, die von volatile geändert wurden, haben die folgenden zwei Attribute:
Shared Variable: Wenn eine Variable im Arbeitsspeicher mehrerer Threads eine Kopie hat, ist diese Variable die gemeinsam genutzte Variable dieser Threads.
Sichtbarkeit: Die Änderung eines Threads zum gemeinsam genutzten variablen Wert kann von anderen Threads rechtzeitig angezeigt werden.
Wenn Sie damit nicht vertraut sind, google es einfach googeln, also werde ich es hier nicht erwähnen. Denken Sie daran, dass Sie beim Betrieb einer gemeinsam genutzten Variablen in mehreren Threads daran denken müssen, eine volatile Modifikation hinzuzufügen.
Aus zeitlichen Einschränkungen müssen wir zuerst noch zuerst zum heutigen Thema kommen. Das Keyword -volatil ist im Interview immer noch leicht zu erkennen, das gleichzeitige Programmierfähigkeiten erfordert. Ich werde es Ihnen später kurz erklären.
Geben Sie den Kopfknoten einer einzelnen verknüpften Liste ein und drucken Sie den Wert jedes Knotens vom Ende bis zum Ende aus.
Wir haben viele verknüpfte Listen, einzelne verknüpfte Listen, zwei-Wege-verknüpfte Listen, Listen mit Ringelementen usw. Dies ist der häufigste einköpfige Listenmodus. In der Regel speichern wir Daten im Datenspeicherbereich, und dann zeigt ein Zeiger auf den nächsten Knoten. Obwohl es in Java kein Zeigerkonzept gibt, passen Java -Referenzen zum Problem.
Wenn wir diese Frage sehen, erkennen wir oft schnell, dass jeder Knoten ein nächstes Attribut hat. Es ist daher sehr einfach, von Anfang bis Ende auszugeben. Daher werden wir also natürlich daran denken, zuerst eine Weile zu verwenden, um alle Knoten herauszunehmen und sie im Array zu speichern, und dann das Array in umgekehrter Reihenfolge durchqueren, damit die Knotenwerte einer einzelnen verknüpften Liste in umgekehrter Reihenfolge gedruckt werden können.
Wir gehen davon aus, dass die Daten des Knotens vom Typ sind. Der Implementierungscode lautet wie folgt:
public class test05 {public static class Node {int Data; Knoten als nächstes; } public static void printlinkreverse (Knotenkopf) {ArrayList <node> nodes = new ArrayList <> (); while (head! = null) {nodes.add (Kopf); Head = Head.Next; } für (int i = nodes.size ()-1; i> = 0; i--) {System.out.print (nodes.get (i) .data + ""); }} public static void main (String [] args) {node head = new node (); head.data = 1; Head.Next = new node (); head.next.data = 2; Head.Next.Next = new node (); head.next.next.data = 3; head.next.next.next.next = new node (); head.next.next.next.data = 4; head.next.next.next.next.next = new node (); head.next.next.next.data = 5; printlinkreverse (Kopf); }}Diese Methode kann in der Tat den Druck der verknüpften Liste der verknüpften Listendaten implementieren, verwendet jedoch offensichtlich zwei vollständige Zyklen mit einer zeitlichen Komplexität von O (n²). usw! Rückwärtsausgabe? Es scheint, dass es eine solche Datenstruktur gibt, die dieses Problem perfekt lösen kann, und diese Datenstruktur ist der Stapel.
Der Stapel ist eine Datenstruktur "Last In First Out". Das Prinzip des Stacks kann unsere Anforderungen besser erfüllen, daher lautet der Implementierungscode wie folgt:
public class test05 {public static class Node {int Data; Knoten als nächstes; } public static void printlinkreverse (Knotenkopf) {Stack <node> stack = new Stack <> (); while (Kopf! = null) {stack.push (Kopf); Head = Head.Next; } while (! stack.isempty ()) {System.out.print (stack.pop (). Daten + ""); }} public static void main (String [] args) {node head = new node (); head.data = 1; Head.Next = new node (); head.next.data = 2; Head.Next.Next = new node (); head.next.next.data = 3; head.next.next.next.next = new node (); head.next.next.next.data = 4; head.next.next.next.next.next = new node (); head.next.next.next.next.data = 5; printlinkreverse (Kopf); }}Da es mit einem Stapel implementiert werden kann, ist es für uns sehr einfach zu glauben, dass die Rekursion dieses Problem auch lösen kann, da Rekursion im Wesentlichen eine Stapelstruktur ist. Um die Linkliste der Reverse Order -Ausgabe zu implementieren, geben wir jedes Mal, wenn wir auf einen Knoten zugreifen, den Knoten dahinter rekursiv aus und dann den Knoten selbst aus. Auf diese Weise wird das Ausgabeergebnis der verknüpften Liste natürlich umgekehrt.
Der Code ist wie folgt:
public class test05 {public static class Node {int Data; Knoten als nächstes; } public static void printLinkreverse (Knotenkopf) {if (head! = null) {printlinkreverse (head.Next); System.out.print (head.data+""); }} public static void main (String [] args) {node head = new node (); head.data = 1; Head.Next = new node (); head.next.data = 2; Head.Next.Next = new node (); head.next.next.data = 3; Head.Next.Next.Next = new node (); head.next.next.next.data = 4; head.next.next.next.next.next.next = new node (); head.next.next.next.next.data = 5; printlinkreverse (Kopf); }} Obwohl der rekursive Code sehr ordentlich aussieht, gibt es ein Problem: Wenn die verknüpfte Liste sehr lang ist, wird er definitiv zu tiefen Funktionsaufrufen führen, die den Funktionsaufrufstapelüberlauf verursachen können. Daher ist der Code, der den Code basierend auf der Schleife anzeigt, besser robust.
Das obige ist der gesamte Inhalt dieses Artikels. Ich hoffe, es wird für das Lernen aller hilfreich sein und ich hoffe, jeder wird Wulin.com mehr unterstützen.