Skip to content

Commit af861a7

Browse files
committed
stacks
1 parent 4ebe848 commit af861a7

File tree

3 files changed

+391
-0
lines changed

3 files changed

+391
-0
lines changed
Loading
48.6 KB
Loading
Lines changed: 391 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,391 @@
1+
{
2+
"cells": [
3+
{
4+
"cell_type": "code",
5+
"execution_count": 1,
6+
"metadata": {
7+
"collapsed": false
8+
},
9+
"outputs": [],
10+
"source": [
11+
"%load_ext watermark"
12+
]
13+
},
14+
{
15+
"cell_type": "code",
16+
"execution_count": 2,
17+
"metadata": {
18+
"collapsed": false
19+
},
20+
"outputs": [
21+
{
22+
"name": "stdout",
23+
"output_type": "stream",
24+
"text": [
25+
"Sebastian Raschka \n",
26+
"last updated: 2016-08-01 \n",
27+
"\n",
28+
"CPython 3.5.1\n",
29+
"IPython 5.0.0\n"
30+
]
31+
}
32+
],
33+
"source": [
34+
"%watermark -a 'Sebastian Raschka' -u -d -v"
35+
]
36+
},
37+
{
38+
"cell_type": "markdown",
39+
"metadata": {},
40+
"source": [
41+
"# Stacks"
42+
]
43+
},
44+
{
45+
"cell_type": "markdown",
46+
"metadata": {},
47+
"source": [
48+
"Stacks are one of the basic, linear datastructures that have the characteristical 2 end points (here: a *top* and a *base*). \n",
49+
"\n",
50+
"![](images/stacks-01.png)"
51+
]
52+
},
53+
{
54+
"cell_type": "markdown",
55+
"metadata": {},
56+
"source": [
57+
"Stacks are also often referred to as LIFO datastructures, which stands for \"last in, first out,\" and we can picture them as \"unwashed dishes\" in our sink: the first plate to remove is the last one we put there and vice versa.\n",
58+
"\n",
59+
"![](images/stacks_02.png)"
60+
]
61+
},
62+
{
63+
"cell_type": "markdown",
64+
"metadata": {},
65+
"source": [
66+
"The idea behind stacks sounds trivial, yet, it is a data structure that is immensely useful in a variety of applications. One example would be the \"back\" button of our web browser, which goes one step back in our search history upon \"clicking\" -- back to the last item we added to the stack. Before we look at another common example, parenthesis matching, let's implement a basic `Stack` class using Python lists as an illustration."
67+
]
68+
},
69+
{
70+
"cell_type": "code",
71+
"execution_count": 3,
72+
"metadata": {
73+
"collapsed": true
74+
},
75+
"outputs": [],
76+
"source": [
77+
"class Stack(object):\n",
78+
" def __init__(self):\n",
79+
" self.stack = []\n",
80+
" \n",
81+
" def add(self, item):\n",
82+
" self.stack.append(item)\n",
83+
" \n",
84+
" def pop(self):\n",
85+
" self.stack.pop()\n",
86+
" \n",
87+
" def peek(self):\n",
88+
" return self.stack[-1]\n",
89+
" \n",
90+
" def size(self):\n",
91+
" return len(self.stack)"
92+
]
93+
},
94+
{
95+
"cell_type": "markdown",
96+
"metadata": {},
97+
"source": [
98+
"Note that the addition and removal of a single item is a O(1) algorithm: it takes linear time to remove or add an item to the top of the stack. In the simple implementation above, we added 2 more convenience methods: a `peek` methods, which lets us look at the top of the stack (i.e., the end of the Python list `self.stack`) and a `size` method, which returns the number of elements that are currently in the stack."
99+
]
100+
},
101+
{
102+
"cell_type": "code",
103+
"execution_count": 4,
104+
"metadata": {
105+
"collapsed": false
106+
},
107+
"outputs": [
108+
{
109+
"name": "stdout",
110+
"output_type": "stream",
111+
"text": [
112+
"size: 2\n",
113+
"top element 1\n",
114+
"size: 1\n",
115+
"top element a\n",
116+
"size: 0\n"
117+
]
118+
}
119+
],
120+
"source": [
121+
"st = Stack()\n",
122+
"\n",
123+
"st.add('a')\n",
124+
"st.add(1)\n",
125+
"print('size:', st.size())\n",
126+
"print('top element', st.peek())\n",
127+
"\n",
128+
"st.pop()\n",
129+
"print('size:', st.size())\n",
130+
"print('top element', st.peek())\n",
131+
"\n",
132+
"st.pop()\n",
133+
"print('size:', st.size())"
134+
]
135+
},
136+
{
137+
"cell_type": "markdown",
138+
"metadata": {},
139+
"source": [
140+
"## Example 1: Matching Paranthesis"
141+
]
142+
},
143+
{
144+
"cell_type": "markdown",
145+
"metadata": {},
146+
"source": [
147+
"Another common application of stacks -- next to the \"back\" button example mentioned earlier -- is syntax checking; matching openining and closing parantheses (e.g., in regex, math equations, etc.) to be specific. "
148+
]
149+
},
150+
{
151+
"cell_type": "code",
152+
"execution_count": 5,
153+
"metadata": {
154+
"collapsed": false
155+
},
156+
"outputs": [],
157+
"source": [
158+
"def check_parens(eq, pair=['(', ')']):\n",
159+
" st = Stack()\n",
160+
" matches = True\n",
161+
" for c in eq:\n",
162+
" if c == pair[0]:\n",
163+
" st.add(c)\n",
164+
" elif c == pair[1]:\n",
165+
" if st.size():\n",
166+
" st.pop()\n",
167+
" else:\n",
168+
" matches = False\n",
169+
" break\n",
170+
" if not matches and st.size():\n",
171+
" matches = False\n",
172+
" return matches"
173+
]
174+
},
175+
{
176+
"cell_type": "code",
177+
"execution_count": 6,
178+
"metadata": {
179+
"collapsed": false
180+
},
181+
"outputs": [
182+
{
183+
"data": {
184+
"text/plain": [
185+
"True"
186+
]
187+
},
188+
"execution_count": 6,
189+
"metadata": {},
190+
"output_type": "execute_result"
191+
}
192+
],
193+
"source": [
194+
"eq1 = '(a + b) * (c + d)'\n",
195+
"check_parens(eq=eq1)"
196+
]
197+
},
198+
{
199+
"cell_type": "markdown",
200+
"metadata": {},
201+
"source": [
202+
"The code above is relatively simple, yet effective. We initialize a new `Stack` and set the `matches` variables to true -- we use the latter to keep track whether the paranthesis are matched or not. Next, we use a for loop to iterate through the string. If we encounter an opening paranthesis, we add it from the stack. If we encounter a closing parenthesis, we try to remove the last opening bracket from the stack. If we encounter a closing bracket but the stack is empty, we already know that the parentheses are not matching, and we can break out the for loop early. \n",
203+
"After we finished iterating through the string, we check if our stack is empty. If it is not, parentheses are not matching.\n",
204+
"\n",
205+
"Here, two more examples:"
206+
]
207+
},
208+
{
209+
"cell_type": "code",
210+
"execution_count": 7,
211+
"metadata": {
212+
"collapsed": false
213+
},
214+
"outputs": [
215+
{
216+
"data": {
217+
"text/plain": [
218+
"False"
219+
]
220+
},
221+
"execution_count": 7,
222+
"metadata": {},
223+
"output_type": "execute_result"
224+
}
225+
],
226+
"source": [
227+
"eq2 = '(a + b) * (c + d))'\n",
228+
"check_parens(eq=eq2)"
229+
]
230+
},
231+
{
232+
"cell_type": "code",
233+
"execution_count": 8,
234+
"metadata": {
235+
"collapsed": false
236+
},
237+
"outputs": [
238+
{
239+
"data": {
240+
"text/plain": [
241+
"False"
242+
]
243+
},
244+
"execution_count": 8,
245+
"metadata": {},
246+
"output_type": "execute_result"
247+
}
248+
],
249+
"source": [
250+
"eq3 = 'a + b) * (c + d)'\n",
251+
"check_parens(eq=eq3)"
252+
]
253+
},
254+
{
255+
"cell_type": "markdown",
256+
"metadata": {},
257+
"source": [
258+
"## Example 2: Decimal to Binary Conversion"
259+
]
260+
},
261+
{
262+
"cell_type": "markdown",
263+
"metadata": {},
264+
"source": [
265+
"Now, let's look at another example, where we are using a stack to convert digits from the decimal into the binary system. For example, the decimal number 135 would be represented as the number 10000111 in the binary system, since\n",
266+
"\n",
267+
"$$1 \\times 2^7 + 0 \\times 2^6 + 0 \\times 2^5 + 0 \\times 2^4 + 0 \\times 2^3 + 1 \\times 2^2 + 1 \\times 2^1 + 1 \\times 2^0 = 135.$$\n"
268+
]
269+
},
270+
{
271+
"cell_type": "code",
272+
"execution_count": 9,
273+
"metadata": {
274+
"collapsed": true
275+
},
276+
"outputs": [],
277+
"source": [
278+
"def decimal_to_binary(number):\n",
279+
" st = Stack()\n",
280+
" while number > 0:\n",
281+
" remainder = number % 2\n",
282+
" st.add(remainder)\n",
283+
" number = number // 2\n",
284+
" binary = ''\n",
285+
" while st.size():\n",
286+
" binary += str(st.peek())\n",
287+
" st.pop()\n",
288+
" return binary"
289+
]
290+
},
291+
{
292+
"cell_type": "markdown",
293+
"metadata": {},
294+
"source": [
295+
"Our conversion function is simple, we iteratively divide the integer number by 2 until we arrive at 0, and for each division, we add the remainder (a 0 or 1) to the stack. Finally, we remove the items one by one from the stack to build a string notation of the binary number."
296+
]
297+
},
298+
{
299+
"cell_type": "code",
300+
"execution_count": 10,
301+
"metadata": {
302+
"collapsed": false
303+
},
304+
"outputs": [
305+
{
306+
"data": {
307+
"text/plain": [
308+
"'10000111'"
309+
]
310+
},
311+
"execution_count": 10,
312+
"metadata": {},
313+
"output_type": "execute_result"
314+
}
315+
],
316+
"source": [
317+
"decimal_to_binary(135)"
318+
]
319+
},
320+
{
321+
"cell_type": "markdown",
322+
"metadata": {},
323+
"source": [
324+
"Finally, let's walk through the solution step by step to make sure we understood it correctly:"
325+
]
326+
},
327+
{
328+
"cell_type": "markdown",
329+
"metadata": {},
330+
"source": [
331+
"- Initialize stack -> []\n",
332+
"\n",
333+
"1.\n",
334+
" 1. 135 % 2 = 1\n",
335+
" 2. add remainder 1 to stack -> [1]\n",
336+
" 3. 135 // 2 = 67\n",
337+
"2.\n",
338+
" 1. 67 % 2 = 1\n",
339+
" 2. add remainder 1 to stack -> [1, 1]\n",
340+
" 3. 67 // 2 = 33\n",
341+
"3.\n",
342+
" 1. 33 % 2 = 1\n",
343+
" 2. add remainder 1 to stack -> [1, 1, 1]\n",
344+
" 3. 33 // 2 = 16\n",
345+
"4.\n",
346+
" 1. 16 % 2 = 0\n",
347+
" 2. add remainder 0 to stack -> [1, 1, 1, 0]\n",
348+
" 3. 16 // 2 = 8\n",
349+
"5.\n",
350+
" 1. 8 % 2 = 0\n",
351+
" 2. add remainder 0 to stack -> [1, 1, 1, 0, 0]\n",
352+
" 3. 8 // 2 = 4\n",
353+
"6.\n",
354+
" 1. 4 % 2 = 0\n",
355+
" 2. add remainder 0 to stack -> [1, 1, 1, 0, 0, 0]\n",
356+
" 3. 4 // 2 = 2\n",
357+
"7.\n",
358+
" 1. 2 % 2 = 0\n",
359+
" 2. add remainder 0 to stack -> [1, 1, 1, 0, 0, 0, 0]\n",
360+
" 3. 2 // 2 = 1\n",
361+
"8.\n",
362+
" 1. 1 % 2 = 1\n",
363+
" 2. add remainder 1 to stack -> [1, 1, 1, 0, 0, 0, 0, 1]\n",
364+
" 3. 1 // 2 = 0\n",
365+
" \n",
366+
"- [1, 1, 1, 0, 0, 0, 0, 1] -> 10000111"
367+
]
368+
}
369+
],
370+
"metadata": {
371+
"kernelspec": {
372+
"display_name": "Python 3",
373+
"language": "python",
374+
"name": "python3"
375+
},
376+
"language_info": {
377+
"codemirror_mode": {
378+
"name": "ipython",
379+
"version": 3
380+
},
381+
"file_extension": ".py",
382+
"mimetype": "text/x-python",
383+
"name": "python",
384+
"nbconvert_exporter": "python",
385+
"pygments_lexer": "ipython3",
386+
"version": "3.5.1"
387+
}
388+
},
389+
"nbformat": 4,
390+
"nbformat_minor": 0
391+
}

0 commit comments

Comments
 (0)