Files
algorithms/python_hw1_notebook.ipynb
2025-02-02 14:27:24 -06:00

943 lines
28 KiB
Plaintext

{
"cells": [
{
"cell_type": "markdown",
"metadata": {
"id": "nnZaXnTfRsvH"
},
"source": [
"\n",
"# **Linked list with Collections**\n"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "VFRnVs8174kz"
},
"source": [
"# **I. Introduction**\n",
"\n",
"Thank you for choosing Python as your main programming language. This is our first homework assignment, and we will write the API for the data structures we will need later in this course.\n",
"\n",
"You will submit the notebook file (.ipynb) and a brief report (pdf file) showcasing the implementation process and outcomes of the code.\n",
"\n",
"**Due date of HW1: 12PM (Noon) Feb 2, 2025**\n",
"\n",
"If you have any questions please contact us via Teams or email: arpanp@uark.edu and maalexra@uark.edu\n",
"\n",
"Several fundamental data type involves *collections* of objects, e.g. Python has list, tuple, set and dictionary, and the *operations* revolving around adding, removing, or examining the objects in the collection. In this assignment, we will look into 3 popular data types, i.e. bag, queue and stack. The main difference among them is the specifications of which objects is to be removed and examined next.\n",
"\n",
"Although we could utilize the Python built-in data type such as list to ease the implementation, it is our goal to introduce and show the importance of *linked* data structures in implementing bags, queues and stacks. Understanding linked lists is pivotal to understanding algorithms and data structures.\n",
"\n"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "614Dz_WxUDcS"
},
"source": [
"# **II.1. Linked List**\n",
"\n",
"> A *linked list* is a recursive data structure that is either empty or a reference to a *node* having a generic item and a reference to a linked list.\n",
"\n",
"In this section, we will introduce linked list, a data structure that is not directly supported by the Python language. As defined above, linked lists make use of *node*, an abstract entity that could contain any kind of data, and *node reference* that aids in building linked lists. This fundamental data structure is very efficient when it comes to writing recursive program.\n",
"\n",
"Python is an object-oriented programming language and we will utilize *class* to define node abstraction.\n",
"\n",
"\n"
]
},
{
"cell_type": "code",
"execution_count": 1,
"metadata": {
"id": "jUNgSbfpLrVP"
},
"outputs": [],
"source": [
"# implementation of Node abstraction\n",
"class Node:\n",
" def __init__(self):\n",
" self.item = None # an item\n",
" self.next = None # a node"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "Z1Vs3D_wefa4"
},
"source": [
"a Node has two attributes: an item and a node. The code looks way too simple as we only override the default constructor by creating 2 variables *item* and *next*, and set them both to None. *item* is a placeholder for any data that we want to structure with a linked list. *next* is a reference to the next node.\n",
"\n",
"##**Q&A**:\n",
"**[Q]**: This node definition only works for singly linked list. What if I want node for doubly linked list?\n",
"\n",
"**[A]**: We can add another attribute *prev* that points to previous node to build doubly linked list. Implementation of our considered data types only requires singly linked list, thus having *prev* is a waste of memory. Our Node definition will be nested inside class definition of other data types, as you will see when we define bag.\n",
"\n",
"With Node definition above, we will construct a very simple linked list that has 3 nodes: first, second and third. Structure of the linked list can be seen below:\n",
"\n",
" first\n",
" |item: \"to\" |\n",
" |next: second| -> second\n",
" |item: \"be\" |\n",
" |next: third | -> third \n",
" |item: \"or\" |\n",
" |next: None | -> None\n"
]
},
{
"cell_type": "code",
"execution_count": 50,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "P7WAf1h8MDMz",
"outputId": "84d35014-3046-4581-d67a-a1bf5ce83abc"
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"to\n",
"be\n",
"or\n"
]
}
],
"source": [
"# initialize 3 nodes\n",
"first = Node()\n",
"second = Node()\n",
"third = Node()\n",
"\n",
"# add content to the node\n",
"first.item = \"to\" # first node\n",
"second.item = \"be\" # second node\n",
"third.item = \"or\" # third node\n",
"\n",
"# building the linked list\n",
"first.next = second\n",
"second.next = third\n",
"\n",
"# iterate through this linked list and print the items\n",
"node = first\n",
"while node is not None:\n",
" print(node.item)\n",
" node = node.next\n",
"del node # delete the temporary node"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "3OiYYtsJvjfB"
},
"source": [
"One big advantage of linked lists is we don't need to tell the size of the list before creating it. The list can always take in new value and remove the current value. We can easily iterate through the list using while loop with the stop conditon that the current node is None. This demo should be enough for us to understand how to build linked list in Python. Let's talk about Bag, Queue and Stack."
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "c-HfkoT-nY65"
},
"source": [
"# **II.2. Bag**\n",
"\n",
"A *bag* is a collection where removing items is not supported. Its purpose is to provide clients with the ability to collect items and iterate through all the items in the bag. Before we implement this data type, let's see exactly what we need for *bag*.\n",
"\n",
"**Bag API**\n",
"```\n",
"class Bag():\n",
" __init__()->None # create an empty bag\n",
" add(item: Item)->None # add an item\n",
" isEmpty()->bool # is the bag empty?\n",
" __len__()->int # number of items in the bag\n",
"```\n",
"From the API, we need 4 methods to replicate the characteristic of *bag*. In fact, we might need more than 4 methods but these are the most important for this data type. The implementation code can be seen in the cell below"
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {
"id": "DDubKANz3jzv"
},
"outputs": [],
"source": [
"from typing import TypeVar\n",
"Item = TypeVar('Item') # don't worry about this, it makes code more readable\n",
"\n",
"class Bag:\n",
" # define the constructor with 2 private attributes\n",
" def __init__(self) -> None:\n",
" self.__N = 0 # number of items - private\n",
" self.__first = None # point to first item in the bag - private\n",
"\n",
" # add an item to bag\n",
" def add(self, item: Item) -> None:\n",
" oldFirst = self.__first\n",
" self.__first = self.Node() # create a new node\n",
" self.__first.item = item # add content to that node\n",
" self.__first.next = oldFirst # create a reference to next node\n",
" self.__N += 1 # increment the size of bag by 1\n",
"\n",
" # nested class Node inside class Bag\n",
" class Node:\n",
" def __init__(self) -> None:\n",
" self.item = None\n",
" self.next = None\n",
"\n",
" # method to check if bag is empty\n",
" def isEmpty(self) -> bool:\n",
" return self.__N == 0\n",
"\n",
" # method to return the size of bag\n",
" def __len__(self) -> int:\n",
" return self.__N\n",
"\n",
" # print the content of the bag\n",
" def __str__(self) -> str:\n",
" output_str = \"[\"\n",
" self.__iter_node = self.__first\n",
" while True:\n",
" if self.__iter_node is not None:\n",
" output_str += f'{self.__iter_node.item}'\n",
" self.__iter_node = self.__iter_node.next\n",
" if self.__iter_node is not None:\n",
" output_str += ','\n",
" else:\n",
" break\n",
" output_str += ']'\n",
" return output_str\n",
"\n",
" # The 2 methods below make the objects iterable\n",
" def __iter__(self):\n",
" self.__iter_node = self.__first\n",
" return self\n",
"\n",
" def __next__(self):\n",
" if self.__iter_node is not None:\n",
" x = self.__iter_node.item\n",
" self.__iter_node = self.__iter_node.next\n",
" return x\n",
" else:\n",
" raise StopIteration\n"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "JBSA53jddNFa"
},
"source": [
"The code implementation above is self-explanatory. Let's create a bag example and see what we can do with it.\n"
]
},
{
"cell_type": "code",
"execution_count": 52,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "HIW4VzuidMiD",
"outputId": "6209586d-e3c9-41f0-9107-a3ccf149ff33"
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"The bag after initialization is []\n",
"bag is empty: True \n",
"\n",
"The size of the bag after adding is 3\n",
"The items in the bag after adding are\n",
"[Fayetteville,1871,University of Arkansas]\n",
"\n",
"Iterate through this bag\n",
"Fayetteville 1871 University of Arkansas "
]
}
],
"source": [
"# create a variable of type Bag\n",
"bag = Bag()\n",
"print(f'The bag after initialization is {bag}')\n",
"\n",
"# check if the bag is empty\n",
"print(f\"bag is empty: {bag.isEmpty()} \\n\")\n",
"\n",
"# let's add some items to this bag. Items could be of any data type\n",
"bag.add(\"University of Arkansas\")\n",
"bag.add(1871)\n",
"bag.add(\"Fayetteville\")\n",
"\n",
"# print the content of bag\n",
"print(f\"The size of the bag after adding is {len(bag)}\") # thanks to __len__()\n",
"print('The items in the bag after adding are')\n",
"print(bag) # thanks to __str__()\n",
"\n",
"# iterate through the bags and print each item\n",
"print(\"\\nIterate through this bag\")\n",
"for item in bag: # thanks to __iter__ and __next__\n",
" print(item, end=' ')"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "6TNz7QQ02C-K"
},
"source": [
"# **III. FIFO Queue** (25 pts)"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "CqrWcdzA2K2e"
},
"source": [
"A *queue* is a collection that is based on the first-in-first-out (FIFO) policy. Whatever item comes in the queue first must leave first. Queues are a natural model for many everyday phenomena, and they play a very important role in many applications. When a client iterates through the items in a queue, the items are processed in the order they were added to the queue. In this section, you have to\n",
"\n",
"\n",
"1. Write the class definition of Queue\n",
"2. Run the test cases that we provide below\n",
"\n",
"*You will get full 25 pts upon successful run of all test cases (including the ones hidden from this file). You have to use linked list to implement queue*.\n",
"\n",
"\n",
"\n",
"**Queue API**\n",
"```\n",
"class Queue():\n",
" __init__()->None # create an empty queue\n",
" enqueue(item: Item)->None # add an item\n",
" dequeue()->Item # remove the least recently added item\n",
" isEmpty()->bool # is the queue empty?\n",
" peek()-> Item # the element at the front without removing it \n",
" __len__()->int # number of items in the queue\n",
"```"
]
},
{
"cell_type": "code",
"execution_count": 22,
"metadata": {
"id": "Praq255-p0cB"
},
"outputs": [],
"source": [
"# Write class definition of queue below this line\n",
"class Queue:\n",
"\n",
" head: Node = None\n",
"\n",
" def enqueue(self, item: Item) -> None:\n",
" if not self.head:\n",
" self.head = Node()\n",
" self.head.item = item\n",
" return None\n",
"\n",
" next: Node | None = self.head.next\n",
" if not next:\n",
" self.head.next = Node()\n",
" self.head.next.item = item\n",
" return None\n",
"\n",
" while next:\n",
" if not next.next:\n",
" next.next = Node()\n",
" next.next.item = item\n",
" return None\n",
" next = next.next\n",
"\n",
" def dequeue(self) -> Item:\n",
" item = self.head.item\n",
" self.head = self.head.next\n",
" return item\n",
"\n",
" def isEmpty(self) -> bool:\n",
" return not self.head\n",
"\n",
" def peek(self) -> Item | None:\n",
" return self.head.item if self.head else None\n",
"\n",
" def __len__(self) -> int:\n",
" l = 0\n",
" for i in self:\n",
" l += 1\n",
"\n",
" return l\n",
"\n",
" def __str__(self) -> str:\n",
" s = \"[\"\n",
"\n",
" for item in self:\n",
" s += f'{str(item)}, '\n",
"\n",
" if len(self) > 0:\n",
" s = s[:-2]\n",
"\n",
" s += \"]\"\n",
"\n",
" return s\n",
"\n",
" def __iter__(self):\n",
" self.__iter_node = self.head\n",
" return self\n",
"\n",
" def __next__(self):\n",
" if self.__iter_node is not None:\n",
" x = self.__iter_node.item\n",
" self.__iter_node = self.__iter_node.next\n",
" return x\n",
" else:\n",
" raise StopIteration\n",
"\n"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "41fOF_APvZ7C"
},
"source": [
"**Test case 1**"
]
},
{
"cell_type": "code",
"execution_count": 23,
"metadata": {
"id": "yrZJlezKq-jd"
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"The queue after initialization is []\n",
"The queue after enqueue is [0, 1, 2, 3, 4]\n"
]
}
],
"source": [
"# initializing queue\n",
"queue = Queue()\n",
"print(f'The queue after initialization is {queue}')\n",
"assert(queue.isEmpty() == True) # check if isEmpty works properly\n",
"\n",
"# add the items to queue\n",
"for i in range(5):\n",
" queue.enqueue(i)\n",
"print(f'The queue after enqueue is {queue}')\n",
"\n",
"assert(queue.isEmpty() == False) # check if isEmpty works properly\n",
"assert(len(queue) == 5) # check if __len__ works properly\n",
"# Peek at the front item\n",
"front_item = queue.peek()\n",
"assert(front_item == 0) #check if peek is working properly"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "m8xY3WEarF0Q"
},
"source": [
"**Test case 2**"
]
},
{
"cell_type": "code",
"execution_count": 24,
"metadata": {
"id": "CK1mYV84rLvb"
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Dequeue the queue\n",
"item dequeued from queue: 0\n",
"queue: [1, 2, 3, 4]\n",
"length of queue: 4\n",
"item dequeued from queue: 1\n",
"queue: [2, 3, 4]\n",
"length of queue: 3\n",
"item dequeued from queue: 2\n",
"queue: [3, 4]\n",
"length of queue: 2\n",
"item dequeued from queue: 3\n",
"queue: [4]\n",
"length of queue: 1\n",
"item dequeued from queue: 4\n",
"queue: []\n",
"length of queue: 0\n",
"\n",
"Queue after enqueue: [5]\n",
"Length of queue: 1\n"
]
}
],
"source": [
"# dequeue the queue\n",
"print(\"Dequeue the queue\")\n",
"while len(queue) > 0:\n",
" item = queue.dequeue()\n",
" print(f'item dequeued from queue: {item}')\n",
" print(f'queue: {queue}')\n",
" print(f'length of queue: {len(queue)}')\n",
"\n",
"assert(queue.isEmpty() == True)\n",
"\n",
"# enqueue the queue\n",
"queue.enqueue(5)\n",
"print(f\"\\nQueue after enqueue: {queue}\")\n",
"print(f\"Length of queue: {len(queue)}\")"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "JqNz1z682MG9"
},
"source": [
"# **IV. Pushdown (LIFO) stack** (25 pts)"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "lWQOklXU2QA1"
},
"source": [
"A *stack* is a collection that is based on the last-in-first-out (LIFO) policy. When we click a hyperlink from a current page, our browser displays the new page. We can keep clicking on hyperlinks to visit new pages, but we can visit the previous page just by clicking the back button. This is one application of stack. In this section, you have to\n",
"\n",
"\n",
"1. Write the class definition of Stack\n",
"2. Run the test cases that we provide below\n",
"\n",
"*You will get full 25 pts upon successful run of all test cases (including the ones hidden from this file). You have to use linked list to implement stack*.\n",
"\n",
"\n",
"**Stack API**\n",
"```\n",
"class Stack():\n",
" __init__()->None # create an empty stack\n",
" push(item: Item)->None # add an item\n",
" pop()->Item # remove the most recently added item\n",
" isEmpty()->bool # is the stack empty?\n",
" peek()-> Item # get the item at the top without removing it.\n",
" __len__()->int # number of items in the stack\n",
"```"
]
},
{
"cell_type": "code",
"execution_count": 35,
"metadata": {
"id": "k50yGJZ2IbUm"
},
"outputs": [],
"source": [
"# Write class definition of stack below this line\n",
"class Stack:\n",
"\n",
" items: list[Item] = []\n",
" head: Node = None\n",
"\n",
" def push(self, item: Item) -> None:\n",
" if not self.head:\n",
" self.head = Node()\n",
" self.head.item = item\n",
" return None\n",
"\n",
" next: Node | None = self.head.next\n",
" if not next:\n",
" self.head.next = Node()\n",
" self.head.next.item = item\n",
" return None\n",
"\n",
" while next:\n",
" if not next.next:\n",
" next.next = Node()\n",
" next.next.item = item\n",
" return None\n",
" next = next.next\n",
"\n",
" def pop(self) -> Item:\n",
" node = self.head\n",
" last = None\n",
"\n",
" while node.next:\n",
" last = node\n",
" node = node.next\n",
"\n",
" if not last:\n",
" self.head = None\n",
" else:\n",
" last.next = None\n",
" return node.item\n",
"\n",
" def isEmpty(self) -> bool:\n",
" return not self.head\n",
"\n",
" def peek(self) -> Item:\n",
" node = None\n",
" for i in self:\n",
" node = i\n",
"\n",
" return node\n",
"\n",
" def __len__(self) -> int:\n",
" l = 0\n",
" for i in self:\n",
" l += 1\n",
"\n",
" return l\n",
"\n",
" def __str__(self) -> str:\n",
" s = \"[\"\n",
"\n",
" for item in self:\n",
" s += f'{str(item)}, '\n",
"\n",
" if len(self) > 0:\n",
" s = s[:-2]\n",
"\n",
" s += \"]\"\n",
"\n",
" return s\n",
"\n",
" def __iter__(self):\n",
" self.__iter_node = self.head\n",
" return self\n",
"\n",
" def __next__(self):\n",
" if self.__iter_node is not None:\n",
" x = self.__iter_node.item\n",
" self.__iter_node = self.__iter_node.next\n",
" return x\n",
" else:\n",
" raise StopIteration\n",
"\n",
"\n"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "O0XM5vgHswRF"
},
"source": [
"**Test case 1**"
]
},
{
"cell_type": "code",
"execution_count": 36,
"metadata": {
"id": "CNXtkCLrA6pK"
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"The stack after initialization is []\n",
"The stack after push is [0, 1, 2, 3, 4]\n"
]
}
],
"source": [
"# initializing stack\n",
"stack = Stack()\n",
"print(f'The stack after initialization is {stack}')\n",
"assert(stack.isEmpty() == True) # check if isEmpty works properly\n",
"\n",
"# add the items to stack\n",
"for i in range(5):\n",
" stack.push(i)\n",
"print(f'The stack after push is {stack}')\n",
"\n",
"assert(stack.isEmpty() == False) # check if isEmpty works properly\n",
"assert(len(stack) == 5) # check if __len__ works properly\n",
"#check if peek is working properly\n",
"top_item = stack.peek()\n",
"assert(top_item==4)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": []
},
{
"cell_type": "markdown",
"metadata": {
"id": "HA5mkNwns179"
},
"source": [
"**Test case 2**"
]
},
{
"cell_type": "code",
"execution_count": 37,
"metadata": {
"id": "1y8IlB2OA6b3"
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Pop the stack\n",
"item dequeued from stack: 4\n",
"stack: [0, 1, 2, 3]\n",
"length of stack: 4\n",
"item dequeued from stack: 3\n",
"stack: [0, 1, 2]\n",
"length of stack: 3\n",
"item dequeued from stack: 2\n",
"stack: [0, 1]\n",
"length of stack: 2\n",
"item dequeued from stack: 1\n",
"stack: [0]\n",
"length of stack: 1\n",
"item dequeued from stack: 0\n",
"stack: []\n",
"length of stack: 0\n",
"\n",
"stack after push: [5]\n",
"length of stack: 1\n"
]
}
],
"source": [
"# pop the stack\n",
"print(\"Pop the stack\")\n",
"while len(stack) > 0:\n",
" item = stack.pop()\n",
" print(f'item dequeued from stack: {item}')\n",
" print(f'stack: {stack}')\n",
" print(f'length of stack: {len(stack)}')\n",
"\n",
"assert(stack.isEmpty() == True)\n",
"\n",
"# enqueue the queue\n",
"stack.push(5)\n",
"print(f\"\\nstack after push: {stack}\")\n",
"print(f\"length of stack: {len(stack)}\")"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "-NDKiwCBIl7Q"
},
"source": [
"# **V. Applications** (50 pts)"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "wEHnP7M-11SJ"
},
"source": [
"**Browser History Management**\n",
"\n",
"The Browser History Management is designed to mimic the navigation history functionality of a web browser. It allows users to:\n",
"\n",
"1. Visit new pages.\n",
"2. Go back to previously visited pages for given steps.\n",
"3. Go forward to pages they have navigated back for given steps.\n",
"4. Retrieve the current page.\n",
"\n",
"\n",
"**Hint**:\n",
"\n",
"Initializes an two empty stack to store the history of pages visited before and to store pages that can be navigated forward to after going back.\n",
"\n",
"1. To visit a page:\n",
" - Push Current Page to back stack\n",
" - Update Current Page\n",
" - Clear forward stack\n",
"2. To go back:\n",
" - iterate until steps is greater than 0 and back stack is not empty\n",
" 1. Push Current Page to forward stack\n",
" 2. Pop from back Stack and Update Current Page\n",
" 3. Decrement steps\n",
"3. To go forward:\n",
" - iterate until steps is greater than 0 and forward stack is not empty\n",
" 1. Push Current Page to back stack\n",
" 2. Pop from forward stack and Update Current Page\n",
" 3. Decrement Steps\n",
"3. To get current page:\n",
" - Return the current page\n",
"\n",
"**Notes**\n",
"\n",
"\n",
"* You have to use stacks implemented before.\n",
"* Each test case is worth 10 points. The other 20 points are in hidden test cases.\n",
"\n"
]
},
{
"cell_type": "code",
"execution_count": 38,
"metadata": {
"id": "brGkmH0dIuFS"
},
"outputs": [],
"source": [
"class BrowserHistory:\n",
" def __init__(self, homepage: str):\n",
" self.current_page = homepage\n",
" # create a backward stack\n",
" self.backward = Stack()\n",
" # create a forward stack\n",
" self.forward_h = Stack()\n",
"\n",
" def visit(self, url: str) -> None:\n",
" # function to visit a new page, updating the history accordingly.\n",
" self.backward.push(self.current_page)\n",
" self.current_page = url\n",
"\n",
" def back(self, steps: int) -> str:\n",
" # function to oves back a specified number of steps in the browsing history.\n",
" for i in range(steps):\n",
" if not self.backward.isEmpty():\n",
" self.forward_h.push(self.current_page)\n",
" self.current_page = self.backward.pop()\n",
"\n",
"\n",
" def forward(self, steps: int) -> str:\n",
" # function to moves forward a specified number of steps in the browsing history.\n",
" for i in range(steps):\n",
" if not self.forward_h.isEmpty():\n",
" self.backward.push(self.current_page)\n",
" self.current_page = self.forward_h.pop()\n",
"\n",
" def current(self) -> str:\n",
" # function to get URL of the current active page\n",
" return self.current_page\n",
"\n"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "L5qdkjWp_v7X"
},
"source": [
"**Test case 1**"
]
},
{
"cell_type": "code",
"execution_count": 39,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "vRyiPCpagKE0",
"outputId": "c11dc0b3-594f-42a0-c585-9097a0bdaac2"
},
"outputs": [],
"source": [
"history = BrowserHistory(\"uark-aicv.github.io\")\n",
"history.visit(\"uark-aicv.github.io/team\")\n",
"history.visit(\"uark-aicv.github.io/research\")\n",
"history.visit(\"uark-aicv.github.io/publications\")\n",
"history.visit(\"uark-aicv.github.io/contact\")\n",
"assert(history.current()=='uark-aicv.github.io/contact')\n"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "C03L51Xg_yZO"
},
"source": [
"**Test case 2**"
]
},
{
"cell_type": "code",
"execution_count": 40,
"metadata": {
"id": "vrimx6IJgKBZ"
},
"outputs": [],
"source": [
"history.back(2)\n",
"assert(history.current()=='uark-aicv.github.io/research')"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "KGQNKaW29dCL"
},
"source": [
"**Test case 3**"
]
},
{
"cell_type": "code",
"execution_count": 41,
"metadata": {
"id": "lvQrZwdr9p89"
},
"outputs": [],
"source": [
"history.forward(1)\n",
"assert(history.current()=='uark-aicv.github.io/publications')"
]
}
],
"metadata": {
"colab": {
"collapsed_sections": [
"nnZaXnTfRsvH",
"VFRnVs8174kz",
"614Dz_WxUDcS",
"c-HfkoT-nY65"
],
"provenance": []
},
"kernelspec": {
"display_name": "Python 3",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.12.0"
}
},
"nbformat": 4,
"nbformat_minor": 1
}