{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "73703282",
   "metadata": {},
   "source": [
    "## Lecture 15, 08 October 2026"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "5a8115d2",
   "metadata": {},
   "source": [
    "### Linked lists"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "f8df0586-8da7-4f78-bf75-6be3ee12a8fe",
   "metadata": {},
   "source": [
    "- Two versions of `append()`\n",
    "    - `appendi()`, iterative\n",
    "    - `appendr()`, recursive\n",
    "    - Dummy `append()` that calls either `appendi()` or `appendr()`\n",
    "        - To avoid problems with `__init__`, `__str__`\n",
    "- Recursive `delete()`\n",
    "    - Note the check to remove spurious empty node after recursive delete"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "id": "86621218-ae0a-4f70-8176-bfc6dea51eda",
   "metadata": {},
   "outputs": [],
   "source": [
    "class List:\n",
    "    def __init__(self,initlist = []):\n",
    "        self.value = None\n",
    "        self.next = None\n",
    "        for x in initlist:\n",
    "            self.append(x)\n",
    "        return\n",
    "\n",
    "    def isempty(self):\n",
    "        return(self.value == None)\n",
    "    \n",
    "    def appendi(self,v):   # append, iterative\n",
    "        if self.isempty():\n",
    "            self.value = v\n",
    "            return\n",
    "        \n",
    "        temp = self\n",
    "        while temp.next != None:\n",
    "            temp = temp.next\n",
    "\n",
    "        temp.next = List()\n",
    "        temp.next.value = v \n",
    "        return\n",
    "\n",
    "    def appendr(self,v):   # append, recursive\n",
    "        if self.isempty():\n",
    "            self.value = v\n",
    "        elif self.next == None:\n",
    "            self.next = List([v])\n",
    "        else:\n",
    "            self.next.appendr(v)\n",
    "        return\n",
    "\n",
    "    def append(self,v):\n",
    "        self.appendr(v)\n",
    "        return\n",
    "\n",
    "    def insert(self,v):\n",
    "        if self.isempty():\n",
    "            self.value = v\n",
    "            return\n",
    "\n",
    "        newnode = List()\n",
    "        newnode.value = v\n",
    "        \n",
    "        # Exchange values in self and newnode\n",
    "        (self.value, newnode.value) = (newnode.value, self.value)\n",
    "\n",
    "        # Switch links\n",
    "        (self.next, newnode.next) = (newnode, self.next)\n",
    "\n",
    "        return\n",
    "\n",
    "    def delete(self,v):   # delete, recursive\n",
    "        if self.isempty():\n",
    "            return\n",
    "\n",
    "        if self.value == v:\n",
    "            if self.next != None:\n",
    "                self.value = self.next.value\n",
    "                self.next = self.next.next\n",
    "            else:\n",
    "                self.value = None\n",
    "            return\n",
    "        else:\n",
    "            if self.next != None:\n",
    "                self.next.delete(v)\n",
    "                # Ensure that there is no empty node at the end of the list\n",
    "                if self.next.value == None:\n",
    "                    self.next = None\n",
    "        return\n",
    "    \n",
    "    def __str__(self):\n",
    "        # Iteratively create a Python list from linked list\n",
    "        # and convert that to a string\n",
    "        selflist = []\n",
    "        if self.isempty():\n",
    "            return(str(selflist))\n",
    "\n",
    "        temp = self\n",
    "        selflist.append(temp.value)\n",
    "        \n",
    "        while temp.next != None:\n",
    "          temp = temp.next\n",
    "          selflist.append(temp.value)\n",
    "\n",
    "        return(str(selflist))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "id": "f7675182-80cc-439d-973a-551b5936df56",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[20, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1]\n"
     ]
    }
   ],
   "source": [
    "l = List()\n",
    "for i in range(20,0,-1):\n",
    "    l.appendr(i)\n",
    "print(l)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "id": "14bad599-dad0-4a53-a396-213f87e5ac00",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[20, 19, 18, 17, 16, 15, 14, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1]\n"
     ]
    }
   ],
   "source": [
    "l.delete(13)\n",
    "print(l)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "a33fef25-8dd0-43d1-ae9a-c25914054aad",
   "metadata": {},
   "source": [
    "- Some performance measurements"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "c6e80c8b-ceb1-4373-a7ac-1cafe921d0e4",
   "metadata": {},
   "source": [
    "- Enhance recursion limit\n",
    "    - $2^{31}-1$ is maximum allowed"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "id": "958b087f-76fc-43d5-baad-6e3d87b33162",
   "metadata": {},
   "outputs": [],
   "source": [
    "import sys\n",
    "sys.setrecursionlimit(2**31-1)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "id": "70b38185-0128-42e2-ba65-0aefe5b22dda",
   "metadata": {},
   "outputs": [],
   "source": [
    "import time"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "aba5d2fe-98b8-412f-9410-3a01bd848960",
   "metadata": {},
   "source": [
    "- Iterative append, quadratic complexity"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "id": "1fe19866",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "1000 0.03675238999858266\n",
      "2000 0.13731428800019785\n",
      "3000 0.2546612810001534\n",
      "4000 0.45674453499668743\n"
     ]
    }
   ],
   "source": [
    "for i in range(1,5):\n",
    "    unit = 1000\n",
    "    l1 = List()\n",
    "    start = time.perf_counter()\n",
    "    for j in range(i*unit):\n",
    "        l1.appendi(j)\n",
    "    elapsed = time.perf_counter() - start\n",
    "    print(i*unit,elapsed)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "9c322128-77ce-4e6c-bcc8-86e69770f842",
   "metadata": {},
   "source": [
    "- Recursive append, also quadratic, but 4x--5x overhead due to recursive calls"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "id": "8275bbb5-8b08-4544-b165-dcfe064e8a8d",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "1000 0.15277522699761903\n",
      "2000 0.574801351998758\n",
      "3000 1.4010387910020654\n",
      "4000 2.4859663140014163\n"
     ]
    }
   ],
   "source": [
    "for i in range(1,5):\n",
    "    unit = 1000\n",
    "    l1 = List()\n",
    "    start = time.perf_counter()\n",
    "    for j in range(i*unit):\n",
    "        l1.appendr(j)\n",
    "    elapsed = time.perf_counter() - start\n",
    "    print(i*unit,elapsed)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "bea293f4-1fbf-4aa7-b938-4804202ab573",
   "metadata": {},
   "source": [
    "### Exception handling"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "id": "18217cbf-9799-4347-b7b1-977f413f62fb",
   "metadata": {},
   "outputs": [
    {
     "ename": "NameError",
     "evalue": "name 'z' is not defined",
     "output_type": "error",
     "traceback": [
      "\u001b[31m---------------------------------------------------------------------------\u001b[39m",
      "\u001b[31mNameError\u001b[39m                                 Traceback (most recent call last)",
      "\u001b[36mCell\u001b[39m\u001b[36m \u001b[39m\u001b[32mIn[8]\u001b[39m\u001b[32m, line 1\u001b[39m\n\u001b[32m----> \u001b[39m\u001b[32m1\u001b[39m print(z)\n",
      "\u001b[31mNameError\u001b[39m: name 'z' is not defined"
     ]
    }
   ],
   "source": [
    "print(z)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "f6c03e06-2735-4ef0-9d4b-f90b20f3c697",
   "metadata": {},
   "source": [
    "### Output\n",
    "\n",
    "- Can control how `print` works\n",
    "- `sep` sets how items are separated (default is a single space)\n",
    "- `end` sets what happens after pring (default is a new line)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "id": "2e602845-c67f-4b1f-884a-c61415f48838",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "5 7\n",
      "5,75 7\n"
     ]
    }
   ],
   "source": [
    "x = 5\n",
    "y = 7\n",
    "print(x,y)\n",
    "print(x,y,sep=\",\",end=\"\")\n",
    "print(x,y)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "9b03a8bd-7dd9-4f1c-a3ce-34bea8947816",
   "metadata": {},
   "source": [
    "#### Input\n",
    "- Read a line from the keyboard using `input()`\n",
    "- Input is terminated by the user typing `Enter`\n",
    "- Returns a string *without* the new line character corresponding to `Enter`"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "id": "96050bb1-fd2e-48d9-b915-0aa242011b5f",
   "metadata": {},
   "outputs": [
    {
     "name": "stdin",
     "output_type": "stream",
     "text": [
      " a\n"
     ]
    }
   ],
   "source": [
    "x = input()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "id": "8a3292c0-f19b-4c5d-97b7-6ad479969659",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'a'"
      ]
     },
     "execution_count": 11,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "x"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "725e94d0-952e-491d-9c02-3bb4f043b060",
   "metadata": {},
   "source": [
    "- Can display a prompt to indicate what is expected"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "id": "3f03cde2-bbf2-485c-b5a8-d69cd67a95de",
   "metadata": {},
   "outputs": [
    {
     "name": "stdin",
     "output_type": "stream",
     "text": [
      "Type something: Hello\n"
     ]
    }
   ],
   "source": [
    "x = input(\"Type something:\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "id": "bd54507a-34a2-44e6-9ccc-54a45aef5d33",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'Hello'"
      ]
     },
     "execution_count": 14,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "x"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "123a2a0d-256c-42fe-a874-7d62de7dc9ad",
   "metadata": {},
   "source": [
    "- User input is not in our control, can trigger errors"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "id": "9077de4a-ca5b-48e0-94f2-0daa239bde9a",
   "metadata": {},
   "outputs": [
    {
     "name": "stdin",
     "output_type": "stream",
     "text": [
      "Enter an integer: abc\n"
     ]
    },
    {
     "ename": "ValueError",
     "evalue": "invalid literal for int() with base 10: 'abc'",
     "output_type": "error",
     "traceback": [
      "\u001b[31m---------------------------------------------------------------------------\u001b[39m",
      "\u001b[31mValueError\u001b[39m                                Traceback (most recent call last)",
      "\u001b[36mCell\u001b[39m\u001b[36m \u001b[39m\u001b[32mIn[15]\u001b[39m\u001b[32m, line 2\u001b[39m\n\u001b[32m      1\u001b[39m xstr = input(\u001b[33m\"Enter an integer:\"\u001b[39m)\n\u001b[32m----> \u001b[39m\u001b[32m2\u001b[39m x = int(xstr)\n\u001b[32m      3\u001b[39m print(x+\u001b[32m5\u001b[39m)\n",
      "\u001b[31mValueError\u001b[39m: invalid literal for int() with base 10: 'abc'"
     ]
    }
   ],
   "source": [
    "xstr = input(\"Enter an integer:\")\n",
    "x = int(xstr)\n",
    "print(x+5)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "3af91f18-45fc-4880-857c-16c069f14cdf",
   "metadata": {},
   "source": [
    "- Need a way for our code to \"trap\" and deal with errors --- *exception handling*\n",
    "- Python statement `pass` is a do-nothing placeholder. Cannot omit `except:` block, nor can you have an empty block."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "a5d3ea09-a024-44b7-8cd8-a06ec77ea7e7",
   "metadata": {},
   "source": [
    "\n",
    "\n",
    "\n",
    "\n",
    "\n",
    "\n",
    "\n",
    "\n",
    "\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "id": "834ef1e9-fe01-45c6-b023-1983f455372d",
   "metadata": {},
   "outputs": [
    {
     "name": "stdin",
     "output_type": "stream",
     "text": [
      "Enter a number:  abc\n",
      "Enter a number:  77\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "77\n"
     ]
    }
   ],
   "source": [
    "invalid = True\n",
    "while (invalid):\n",
    "    try:\n",
    "        xstr = input(\"Enter a number: \")\n",
    "        xint = int(xstr)\n",
    "        invalid = False\n",
    "    except:\n",
    "        pass\n",
    "print(xint)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "b3d3d706-f5e8-4325-99e5-0ea866338e56",
   "metadata": {},
   "source": [
    "- A refined version that prints a diagnostic message to ask the user to retry"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "id": "a1cdf5c3-8698-4e79-95da-15c191112333",
   "metadata": {},
   "outputs": [
    {
     "name": "stdin",
     "output_type": "stream",
     "text": [
      "Enter a number:  abc\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Try again:\n"
     ]
    },
    {
     "name": "stdin",
     "output_type": "stream",
     "text": [
      "Enter a number:  def\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Try again:\n"
     ]
    },
    {
     "name": "stdin",
     "output_type": "stream",
     "text": [
      "Enter a number:  88\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "88\n"
     ]
    }
   ],
   "source": [
    "invalid = True\n",
    "tryagain = False\n",
    "while (invalid):\n",
    "    try:\n",
    "        if tryagain:\n",
    "            print(\"Try again:\")\n",
    "        xstr = input(\"Enter a number: \")\n",
    "        xint = int(xstr)\n",
    "        invalid = False\n",
    "    except:\n",
    "        tryagain = True\n",
    "print(xint)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "a073f234-181a-47b9-8f39-43a0c259f7a5",
   "metadata": {},
   "source": [
    "- Catch a specific type of exception"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "id": "9a1a0f36-ff84-4533-9e0a-5312cb68a072",
   "metadata": {},
   "outputs": [
    {
     "ename": "ValueError",
     "evalue": "invalid literal for int() with base 10: 'abc'",
     "output_type": "error",
     "traceback": [
      "\u001b[31m---------------------------------------------------------------------------\u001b[39m",
      "\u001b[31mValueError\u001b[39m                                Traceback (most recent call last)",
      "\u001b[36mCell\u001b[39m\u001b[36m \u001b[39m\u001b[32mIn[18]\u001b[39m\u001b[32m, line 1\u001b[39m\n\u001b[32m----> \u001b[39m\u001b[32m1\u001b[39m int(\u001b[33m\"abc\"\u001b[39m)\n",
      "\u001b[31mValueError\u001b[39m: invalid literal for int() with base 10: 'abc'"
     ]
    }
   ],
   "source": [
    "int(\"abc\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "id": "fdaa4a37-5c54-4153-9983-2bd118dd9186",
   "metadata": {},
   "outputs": [
    {
     "name": "stdin",
     "output_type": "stream",
     "text": [
      "Enter a number:  xyz\n",
      "Enter a number:  88\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "88\n"
     ]
    }
   ],
   "source": [
    "invalid = True\n",
    "while (invalid):\n",
    "    try:\n",
    "        xstr = input(\"Enter a number: \")\n",
    "        xint = int(xstr)\n",
    "        invalid = False\n",
    "    except ValueError:\n",
    "        pass\n",
    "print(xint)"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "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.13.5"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
