2015-04-21 3 views
5

Это мой первый вопрос в StackOverFlow: Я изучаю интервью с помощью книги «Cracking code interview» (5th Edition), , и я решал следующую проблему:Использование класса оболочки вместо статических переменных

Внедрите функцию, чтобы проверить, является ли двоичное дерево двоичным деревом поиска (Q 4.5 стр. 86).

Прежде чем двигаться дальше, я хотел бы, чтобы напомнить вам разницу между двоичным деревом поиска для простого двоичного дерева:

Двоичного дерево поиска накладывает условие, что для всех узлов, то левые дети меньше или равны текущему узлу, что меньше всех правильных узлов.

Таким образом, одно из решений, предлагаемое книгой, заключается в том, чтобы сканировать дерево с помощью обхода в порядке и на лету, чтобы проверить, больше ли каждый посещенный нами узел, чем последний, и предполагает, что дерево не может имеют одинаковые значения:

public static int last_printed = Integer.MIN_VALUE; 
public static boolean checkBST(TreeNode n) { 
    if(n == null) return true; 

     // Check/recurse left 
     if (!checkBST(n.left)) return false; 

     // Check current 
     if (n.data <= last_printed) return false; 
     last_printed = n.data; 

     // Check/recurse right 
     if (!checkBST(n.right)) return false; 

     return true; // All good! 
} 

Теперь здесь все хорошо, но в книге цитаты:

Если вам не нравится использование статических переменных, то вы можете настроить этот код для использования класса-оболочки для целого числа, как показано ниже:

Class WrapInt { 
    public int value; 
}  

После чтения на класс обертку все здесь и в других веб-сайтах я просто не мог прийти к выводу, как и почему я должен использовать класс-обертку здесь вместо статической переменной?

ответ

2

Это механизм, благодаря которому вы можете создать экземпляр WrapInt и передать его. Затем выставляете значение только коду, который должен знать об этом, а не публичную статическую не конечную переменную, к которой можно получить доступ и изменить из любого места.

Причина, по которой у вас есть класс-оболочка, заключается в том, что примитивы Java являются передаваемыми по значению; проходящий вокруг int, а затем обновление не будет распространять изменения через остальную часть вашей системы.

Это будет выглядеть следующим образом:

public static boolean checkBST(TreeNode n) { 
    WrapInt counter = new WrapInt(); 
    return checkBST(n, counter); 
} 

public static boolean checkBST(TreeNode n, WrapInt counter) { 
    if(n == null) return true; 

     // Check/recurse left 
     if (!checkBST(n.left, counter)) return false; 

     // Check current 
     if (n.data <= counter.value) return false; 
     counter.value = n.data; 

     // Check/recurse right 
     if (!checkBST(n.right, counter)) return false; 

     return true; // All good! 
} 
+0

Спасибо за быстрый ответ. поэтому в основном для использования обертки мне нужно будет создать экземпляр и передать его как один из параметров функции? – vigdora

+2

Да, потому что это позволяет checkBST оставаться статическим методом без сохранения. Затем он позволяет использовать метод из многопоточных потоков, поскольку глобальное состояние отсутствует. –

1

Здесь вы идете:

public static boolean checkBST(TreeNode n) { 
    WrapInt i = new WrapInt(); 
    i.value = INTEGER.MIN_VALUE; 
    doCheckBST(n, i); 
} 

private static boolean doCheckBST(TreeNode n, WrapInt last_printed) { 
if(n == null) return true; 

    // Check/recurse left 
    if (!checkBST(n.left, last_printed)) return false; 

    // Check current 
    if (n.data <= last_printed.value) return false; 
    last_printed.value = n.data; 

    // Check/recurse right 
    if (!checkBST(n.right, last_printed)) return false; 

    return true; // All good! 
} 
1

Если есть вероятность того, что там будет работать 2+ сорта одновременно. Статичность будет использоваться для обеих сортировок. Обе сортировки имеют доступ к одному и тому же статическому значению.

//thread 1 
Sorting A = new Sorting(5,9,8); 
A.sort(); 

//thread 2 
Sorting B = new Sorting(999,100,7); 
B.sort(); 

Мы не можем предсказать, что/как обрабатывается поток.

Так что это может закончиться в

A.checkBST(5) // last_printed = 5 
B.checkBST(999) // last_printed = ?? 
B.checkBST(100) // last_printed = ?? 
A.checkBST(9) // last_printed = ?? 

... ...

Если у каждого экземпляра экземпляра есть свой собственный last_printed, у вас не будет проблем с синхронизацией.

0

Проблема со статической переменной заключается в том, что другой класс/метод или что-то может ее изменить, и он сломает ваш код. Вы можете сделать это так:

Class WrapInt { 
public int value=Integer.MIN_VALUE; 
} 

public static boolean checkBST(TreeNode n,WrapInt lastPrinted) { 
if(n == null) return true; 

    // Check/recurse left 
    if (!checkBST(n.left,lastPrinted)) return false; 

    // Check current 
    if (n.data <= lastPrinted.value) return false; 
    lastPrinted.value = n.data; 

    // Check/recurse right 
    if (!checkBST(n.right,lastPrinted)) return false; 

    return true; // All good! 

}

1

Я думаю, что это более формальный способ, как избежать публичного статического контекста собственности (например, для безопасности потока), который не является оптимальным подходом в программировании объекта , Но существуют стандартные примитивные классы-оболочки как: https://docs.oracle.com/javase/7/docs/api/java/lang/Integer.html , которые могут использоваться вместо новых классов. Обычно шаблон Wrapper может быть более общим, чем ваш пример: What is a wrapper class?