背景
前两篇文章介绍了 Queue 的实现,很多类库都引入了 Deque,Deque 可以两头添加和删除,然后在 Deque 之上构建 Queue 和 Stack。
Deque
代码
1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Text; 5 using System.Threading.Tasks; 6 7 namespace DataStuctureStudy.Deques 8 { 9 public class Deque<T> 10 { 11 private T[] _items = new T[0]; 12 private int _size = 0; 13 private int _head = -1; 14 private int _tail = -1; 15 16 private void AllocateNewArray() 17 { 18 int newLength = (_size == 0) ? 4 : _size * 2; 19 20 T[] newArray = new T[newLength]; 21 22 if (_size > 0) 23 { 24 // copy contents... 25 // if the array has no wrapping, just copy the valid range 26 // else copy from head to end of the array and then from 0 to the tail 27 28 // if tail is less than head we've wrapped 29 var newIndex = 0; 30 if (_tail < _head) 31 { 32 // copy the _items[head].._items[end] -> newArray[0]..newArray[N] 33 for (int index = _head; index < _items.Length; index++) 34 { 35 newArray[newIndex] = _items[index]; 36 newIndex++; 37 } 38 39 // copy _items[0].._items[tail] -> newArray[N+1].. 40 for (int index = 0; index <= _tail; index++) 41 { 42 newArray[newIndex] = _items[index]; 43 newIndex++; 44 } 45 } 46 else 47 { 48 // copy the _items[head].._items[tail] -> newArray[0]..newArray[N] 49 for (int index = _head; index <= _tail; index++) 50 { 51 newArray[newIndex] = _items[index]; 52 newIndex++; 53 } 54 } 55 _head = 0; 56 _tail = _size - 1; // compensate for the extra bump 57 } 58 else 59 { 60 // nothing in the array 61 _head = -1; 62 _tail = -1; 63 } 64 65 _items = newArray; 66 } 67 68 public void EnqueueFirst(T item) 69 { 70 // if the array needs to grow 71 if (_items.Length == _size) 72 { 73 AllocateNewArray(); 74 } 75 76 // since we know the array isn't full and _head is greater than 0 77 // we know the slot in front of head is open 78 if (_head > 0) 79 { 80 _head--; 81 } 82 else 83 { 84 // otherwise we need to wrap around to the end of the array 85 _head = _items.Length - 1; 86 if (_tail == -1) 87 { 88 _tail = _head; 89 } 90 } 91 _items[_head] = item; 92 _size++; 93 } 94 95 public void EnqueueLast(T item) 96 { 97 // if the array needs to grow 98 if (_items.Length == _size) 99 { 100 AllocateNewArray(); 101 } 102 103 // now we have a properly sized array and can focus on wrapping issues. 104 // if _tail is at the end of the array we need to wrap around 105 if (_tail == _items.Length - 1) 106 { 107 _tail = 0; 108 } 109 else 110 { 111 _tail++; 112 113 if (_head == -1) 114 { 115 _head = _tail; 116 } 117 } 118 _items[_tail] = item; 119 _size++; 120 } 121 122 public T DequeueFirst() 123 { 124 if (_size == 0) 125 { 126 throw new InvalidOperationException("The deque is empty"); 127 } 128 129 T value = _items[_head]; 130 131 if (_head == _items.Length - 1) 132 { 133 // if the head is at the last index in the array - wrap around. 134 _head = 0; 135 } 136 else 137 { 138 // move to the next slot 139 _head++; 140 } 141 _size--; 142 return value; 143 } 144 145 public T DequeueLast() 146 { 147 if (_size == 0) 148 { 149 throw new InvalidOperationException("The deque is empty"); 150 } 151 152 T value = _items[_tail]; 153 154 if (_tail == 0) 155 { 156 // if the tai is at the first index in the array - wrap around. 157 _tail = _items.Length - 1; 158 } 159 else 160 { 161 // move to the previous slot 162 _tail--; 163 } 164 _size--; 165 return value; 166 } 167 168 public T PeekFirst() 169 { 170 if (_size == 0) 171 { 172 throw new InvalidOperationException("The deque is empty"); 173 } 174 return _items[_head]; 175 } 176 177 public T PeekLast() 178 { 179 if (_size == 0) 180 { 181 throw new InvalidOperationException("The deque is empty"); 182 } 183 return _items[_tail]; 184 } 185 186 public int Count 187 { 188 get 189 { 190 return _size; 191 } 192 } 193 } 194 }