Сценарий интервью" последние 100 байт"
Я получил этот вопрос в интервью на днях и хотел бы знать некоторые наилучшие возможные ответы(я не очень хорошо ответил Ха-ха):
сценарий: существует веб-страница, которая отслеживает байты, отправленные по некоторой сети. Каждый раз, когда байт отправляется функция recordByte () вызывается передача этого байта, это может произойти сотни тысяч раз в день. На этой странице есть кнопка, которая при нажатии отображает последние 100 байт, переданные в recordByte () on экран (он делает это, вызывая метод печати ниже).
следующий код-это то, что мне дали и попросили заполнить:
public class networkTraffic {
public void recordByte(Byte b){
}
public String print() {
}
}
каков наилучший способ хранения 100 байт? Список? Любопытно, как лучше всего это сделать.
7 ответов:
что-то вроде этого (кольцевой буфер):
byte[] buffer = new byte[100]; int index = 0; public void recordByte(Byte b) { index = (index + 1) % 100; buffer[index] = b; } public void print() { for(int i = index; i < index + 100; i++) { System.out.print(buffer[i % 100]); } }
преимущества использования кругового буфера:
- вы можете зарезервировать пространство статически. В сетевом приложении реального времени (VoIP, streaming,..)это часто делается потому, что вам не нужно хранить все данные передачи, а только окно, содержащее новые байты для обработки.
- это быстро: может быть реализован с массивом с чтения и записи стоимости O (1).
Я не знаю java, но должна быть концепция очереди, в которой вы будете ставить в очередь байты до тех пор, пока количество элементов в очереди не достигнет 100, и в этот момент Вы будете ставить в очередь один байт, а затем ставить в очередь другой.
public void recordByte(Byte b) { if (queue.ItemCount >= 100) { queue.dequeue(); } queue.enqueue(b); }
вы можете распечатать, заглянув в элементы:
public String print() { foreach (Byte b in queue) { print("X", b); // some hexadecimal print function } }
Кольцевой Буфер используя массив:
- массив из 100 байт
- следите за тем, где находится индекс головы i
- на
recordByte()
поместите текущий байт в A[i] и i = i+1% 100;- на
print()
, return subarray(i+1, 100) конкатенация с subarray (0, i)очереди использование связанного списка (или очереди java):
- на
recordByte()
добавить новый байт в конец- если чтобы новая длина была больше 100, удалите первый элемент
- на
print()
просто распечатайте список
вот мой код. Это может показаться немного неясным, но я уверен, что это самый быстрый способ сделать это (по крайней мере, это будет в C++, не так уверен в Java):
public class networkTraffic { public networkTraffic() { _ary = new byte[100]; _idx = _ary.length; } public void recordByte(Byte b){ _ary[--_idx] = b; if (_idx == 0) { _idx = _ary.length; } } private int _idx; private byte[] _ary; }
некоторые замечания:
- данные не выделяются / освобождаются при вызове recordByte ().
- я не использовал%, потому что это медленнее, чем прямое сравнение и использование if (прогнозирование ветвей может помочь и здесь)
--_idx
быстрее_idx--
потому что нет задействована временная переменная.- Я считаю назад до 0, потому что тогда мне не нужно получать
_ary.length
каждый раз в вызове, но только каждые 100 раз, когда достигается первая запись. Возможно, в этом нет необходимости, компилятор мог бы позаботиться об этом.- если было менее 100 вызовов recordByte (), остальное-нули.
проще всего засунуть его в массив. Максимальный размер, который может вместить массив, составляет 100 байт. Продолжайте добавлять байты по мере их потоковой передачи из интернета. После того, как первые 100 байт находятся в массиве, когда приходит 101-й байт, удалите байт в голове (т. е. 0-й). Продолжай делать это. Это в основном очередь. Концепция ФИФО. После завершения загрузки, у вас остаются последние 100 байт.
не только после загрузки, но в любой момент времени, этот массив будет иметь последние 100 байт.
@Yottagray не получает, где проблема? Кажется, существует ряд общих подходов (массив, круговой массив и т. д.) и ряд языковых подходов (byteArray и т. д.). Я что-то упустил?
многопоточное решение с неблокирующим вводом / выводом:
private static final int N = 100; private volatile byte[] buffer1 = new byte[N]; private volatile byte[] buffer2 = new byte[N]; private volatile int index = -1; private volatile int tag; synchronized public void recordByte(byte b) { index++; if (index == N * 2) { //both buffers are full buffer1 = buffer2; buffer2 = new byte[N]; index = N; } if (index < N) { buffer1[index] = b; } else { buffer2[index - N] = b; } } public void print() { byte[] localBuffer1, localBuffer2; int localIndex, localTag; synchronized (this) { localBuffer1 = buffer1; localBuffer2 = buffer2; localIndex = index; localTag = tag++; } int buffer1Start = localIndex - N >= 0 ? localIndex - N + 1 : 0; int buffer1End = localIndex < N ? localIndex : N - 1; printSlice(localBuffer1, buffer1Start, buffer1End, localTag); if (localIndex >= N) { printSlice(localBuffer2, 0, localIndex - N, localTag); } } private void printSlice(byte[] buffer, int start, int end, int tag) { for(int i = start; i <= end; i++) { System.out.println(tag + ": "+ buffer[i]); } }
просто для галочки. Как насчет использования
ArrayList<Byte>
? Сказать, почему нет?public class networkTraffic { static ArrayList<Byte> networkMonitor; // ArrayList<Byte> reference static { networkMonitor = new ArrayList<Byte>(100); } // Static Initialization Block public void recordByte(Byte b){ networkMonitor.add(b); while(networkMonitor.size() > 100){ networkMonitor.remove(0); } } public void print() { for (int i = 0; i < networkMonitor.size(); i++) { System.out.println(networkMonitor.get(i)); } // if(networkMonitor.size() < 100){ // for(int i = networkMonitor.size(); i < 100; i++){ // System.out.println("Emtpy byte"); // } // } } }