Docsity
Docsity

Prepare for your exams
Prepare for your exams

Study with the several resources on Docsity


Earn points to download
Earn points to download

Earn points by helping other students or get them with a premium plan


Guidelines and tips
Guidelines and tips

Lecture 5: Stacks and Queues, Study notes of Data Structures and Algorithms

A “stack” is another example of an abstract data type. A stack has the following behaviors / functions: push(value) (or add(value)) - place an ...

Typology: Study notes

2022/2023

Uploaded on 05/11/2023

anahitay
anahitay 🇺🇸

4.7

(16)

255 documents

1 / 43

Toggle sidebar

This page cannot be seen from the preview

Don't miss anything!

bg1
Wednesday, April 11, 2018
Programming Abstractions!
Spring 2018!
Stanford University !
Computer Science Department!
Lecturer: Chris Gregg!
reading:!
Programming Abstractions in C++, Chapter 5.2-5.3
CS 106B
Lecture 5: Stacks and Queues
pf3
pf4
pf5
pf8
pf9
pfa
pfd
pfe
pff
pf12
pf13
pf14
pf15
pf16
pf17
pf18
pf19
pf1a
pf1b
pf1c
pf1d
pf1e
pf1f
pf20
pf21
pf22
pf23
pf24
pf25
pf26
pf27
pf28
pf29
pf2a
pf2b

Partial preview of the text

Download Lecture 5: Stacks and Queues and more Study notes Data Structures and Algorithms in PDF only on Docsity!

Wednesday, April 11, 2018

Programming Abstractions

Spring 2018

Stanford University

Computer Science Department

Lecturer: Chris Gregg

reading:

Programming Abstractions in C++, Chapter 5.2-5.

CS 106B Lecture 5: Stacks and Queues

Today's Topics

• Logistics:

• LIFE due on Thursday!

• Python to C++ session: 1:30PM-2:20PM Friday in Skilling Auditorium (will be

recorded)

• Pair Programming: Rules and strategies

• Do we have to implement a Vector with an array?

• We can implement the Vector Abstract Data Type any way we want!

• Efficiency of element manipulation

• Stacks

• Queues

Real Life Cellular Automata?

A Lizard With Scales That Behave Like a Computer Simulation

Vector ("dynamic array") Review

  • Pop quiz: what gives better speed, inserting and removing at the beginning or at the end of a Vector, and what is the Big O? Answer: At the end (no moving of elements necessary) O(1)
  • Pop quiz: If a Vector has n elements, and we are going to insert somewhere into the Vector, what is the maximum number of elements that must be moved? Answer: n
  • Pop quiz: If a Vector has n elements, and we are going to insert somewhere into the Vector, what is the minimum number of elements that must be moved? Answer: 0

Vector: Does the user care how it is implemented? int main() { Vector states; // manually add in alphabetic order states.add("California"); states.insert(0,"Alaska"); states.add("Texas"); states.insert(3,"Utah"); states.insert(2,"Nebraska"); cout << "Originals: " << states.toString() << endl; // for testing // revolution happens states.remove(3); // Texas cout << "After removing Texas: " << states.toString() << endl; return 0; } Consider the following program that uses a Vector: From the perspective of the user, the Vector class needs to have certain behaviors, but the user isn't really concerned with how those behaviors are implemented under the hood. This is the idea behind an ADT -- the Vector needs to have add(), insert(), and remove() functions, but the fact that it is an array under the hood is not relevant if you just want certain behaviors. So...

Vector: Implemented with Moon Monkeys® We could imagine implementing the Stanford Library Vector using Moon Monkeys®, who keep all of our data on the Moon, and simply pass back the results of our functions as we need them. Vector states; states.add("California"); For these statements, we call up the Moon Monkeys, and say "we want a Vector that holds strings," and then we radio up to them, 'Please add "California" to the Vector.' Is this efficient? No. Does it meet the requirements of our Vector ADT? Yes. That is the principle idea behind ADTs: the functional behavior is what matters, not the implementation.

Stacks The push, pop, and top operations are the only operations allowed by the stack ADT, and as such, only the top element is accessible. Therefore, a stack is a “Last-In-First-Out” (LIFO) structure: the last item in is the first one out of a stack. 4 2 5 7 3 PUSH POP TOP

Stacks Despite the stack’s limitations (and indeed, because of them), the stack is a very frequently used ADT. In fact, most computer architectures implement a stack at the very core of their instruction sets — both push and pop are assembly code instructions. Stack operations are so useful that there is a stack built in to every program running on your PC — the stack is a memory block that gets used to store the state of memory when a function is called, and to restore it when a function returns. Why are stacks used to when functions are called? Let’s say we had a program like this: What happens to the state of the system as this program runs? main() { function1(); return; } function1() { function2(); return; } function2() { function3(); return; }

Stacks What are some downsides to using a stack?

  • No random access. You get the top, or nothing.
  • No walking through the stack at all — you can only reach an element by popping all the elements higher up off first
  • No searching through a stack.
  • Useful for lots of problems -- many real-world problems can be solved with a Last- In-First-Out model (we'll see one in a minute)
  • Very easy to build one from an array such that access is guaranteed to be fast.
  • Where would you have the top of the stack if you built one using a Vector? Why would that be fast? What are some benefits to using a stack?

Reversing the words in a sentence Let's build a program from scratch that reverses the words in a sentence. Goal: reverse the words in a sentence that has no punctuation other than letters and spaces. How might we do this?

  1. Use a stack
  2. Read characters in a string and place them in a new word.
  3. When we get to a space, push that word onto the stack, and reset the word to be empty.
  4. Repeat until we have put all the words into the stack.
  5. Pop the words from the stack one at a time and print them out.

More Advanced Stack Example When you were first learning algebraic expressions, your teacher probably gave you a problem like this, and said, "What is the result?" 5 * 4 - 8 / 2 + 9 The class got all sorts of different answers, because no one knew the order of operations yet (the correct answer is 25, by the way). Parenthesis become necessary as well (e.g., 10 / (8-3)). As it turns out, there is a "better" way! We can use a system of arithmetic called "postfix" notation — the expression above would become the following: This is a somewhat annoying problem — it would be nice if there were a better way to do arithmetic so we didn't have to worry about order of operations and parenthesis. 5 4 * 8 2 / - 9 + (^) Wat?

Postfix Example Postfix notation* works like this: Operands (the numbers) come first, followed by an operator (+, -, *, /, etc.). When an operator is read in, it uses the previous operands to perform the calculation, depending on how many are needed (most of the time it is two). So, to multiply 5 and 4 in postfix, the postfix is 5 4 * To divide 8 by 2, it is 8 2 / There is a simple and clever method using a stack to perform arithmetic on a postfix expression: (talk to your neighbor about how you might do this!) 5 4 * 8 2 / - 9 + *Postfix notation is also called "Reverse Polish Notation" (RPN) because in the 1920s a Polish logician named Jan Łukasiewicz invented "prefix" notation, and postfix is the opposite of postfix, and therefore so-called "Reverse Polish Notation" Read the input and push numbers onto a stack until you reach an operator. When you see an operator, apply the operator to the two numbers that are popped from the stack. Push the resulting value back onto the stack. When the input is complete, the value left on the stack is the result.

Postfix Example Code // Postfix arithmetic, implementing +, -, , / #include #include "console.h" #include "simpio.h" #include "stack.h" using namespace std; const string OPERATORS = "+-x/"; const string SEPARATOR = " "; // function prototypes double parsePostfix(string expression); string getNextToken(string &expression); void performCalculation(Stack &s, char op); Top of program: Uses a stack Allows * or x for multiplication Three functions

Postfix Example Code main():

int main() {

string expression;

double answer;

do {

expression = getLine("Please enter a postfix expression (blank to quit): ");

answer = parsePostfix(expression);

cout << "The answer is: " << answer << endl << endl;

} while (expression != "");

return 0;