Во вчерашнем режиме реализации Java Singleton наш механизм блокировки двойной проверки представил volatile ключевое слово из-за проблемы повторного порядка. Многие друзья спросили меня, зачем мне добавлять volatile ключевое слово? А какой волшебный эффект это оказывает?
Что касается volatile слова, мы кратко упомянули во вчерашнем объяснении: общие переменные, модифицированные volatile будут иметь следующие два атрибута:
Общая переменная: если переменная имеет копию в рабочей памяти нескольких потоков, то эта переменная является общей переменной этих потоков.
Видимость: модификация потока к значению общей переменной может быть своевременно видно другими потоками.
Для переупорядочения, если вы не знакомы с этим, просто Google It, поэтому я не буду упоминать об этом здесь. Просто помните, что при использовании общей переменной в нескольких потоках вы должны помнить, чтобы добавить летучую модификацию.
Из -за ограничений по времени мы все еще должны сначала добраться до сегодняшней темы. Ключевое слово volatile по -прежнему легко обнаружить в интервью, которое требует параллельных навыков программирования. Я кратко объясню это вам позже.
Введите узел головы одного связанного списка и распечатайте значение каждого узла с конца до конца.
У нас есть много связанных списков, одиночных списков, двусторонних связанных списков, списков кольца и т. Д. Это наиболее распространенный режим списка с одним связанным списком. Мы обычно храним данные в области хранения данных, а затем указывает на следующий узел. Хотя в Java нет концепции указателя, ссылки на Java соответствуют проблеме.
Когда мы видим этот вопрос, мы часто быстро понимаем, что у каждого узла есть следующий атрибут, поэтому очень просто выводить от начала до конца. Таким образом, мы, естественно, будем думать о том, чтобы сначала использовать цикл while, чтобы снять все узлы и сохранить их в массиве, а затем пересечь массив в обратном порядке, чтобы значения узла одного связанного списка можно было напечатать в обратном порядке.
Мы предполагаем, что данные узла имеют тип int. Код реализации выглядит следующим образом:
public Class Test05 {public Static Class Node {int data; Узел следующий; } public static void printlinkReverse (node head) {arraylist <node> nodes = new ArrayList <> (); while (Head! = null) {nodes.add (head); Head = Head.next; } for (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.next.data = 5; printlinkreverse (голова); }}Этот метод действительно может реализовать печать обратного порядка связанных данных списка, но он, очевидно, использует два полных цикла, с сложностью времени O (N²). и т. д! Обратный выход? Кажется, что существует такая структура данных, которая может идеально решить эту проблему, и эта структура данных является стеком.
Стек является структурой данных «Последний в первом выходе». Принцип стека может лучше соответствовать нашим требованиям, поэтому код реализации выглядит следующим образом:
public Class Test05 {public Static Class Node {int data; Узел следующий; } public static void printlinkReverse (node head) {Stack <node> Stack = new Stack <> (); while (Head! = null) {stack.push (head); Head = Head.next; } while (! Stack.isempty ()) {System.out.print (Stack.pop (). 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.next.data = 5; printlinkreverse (голова); }}Поскольку он может быть реализован с использованием стека, нам очень легко думать, что рекурсия также может решить эту проблему, потому что рекурсия по сути является структурой стека. Чтобы реализовать список выходных ссылок на обратный заказ, каждый раз, когда мы получаем доступ к узлу, мы сначала рекурсивно выводим узел позади него, а затем выводим сам узел. Таким образом, результат вывода связанного списка, естественно, будет изменен.
Код заключается в следующем:
public Class Test05 {public Static Class Node {int data; Узел следующий; } public static void printlinkReverse (node head) {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 (голова); }} Хотя рекурсивный код действительно выглядит очень аккуратно, возникает проблема: когда связанный список очень длинный, он определенно приведет к глубокому уровню вызовов функций, что может привести к переполнению стека вызовов функции. Поэтому код, который отображает код на основе цикла, лучше.
Выше всего содержание этой статьи. Я надеюсь, что это будет полезно для каждого обучения, и я надеюсь, что все будут поддерживать Wulin.com больше.