2026-02-18
baginterface.pyArrayBag class, without changes to the LinkedBag classLinkedBag class are those that cannot avoid this direct access to data:__init____iter__clearaddremove__init__ method in LinkedBag is to create the instance variables and give them initial valuesself.items is now an external pointer instead of an arrayNone, the state of an empty linked structureelf.items refers to the first node in the linked structure"""
File: linkedbag.py
"""
from node import Node
class LinkedBag(object):
"""A link-based bag implementation."""
# Constructor
def __init__(self, sourceCollection = None):
"""Sets the initial state of self, which includes the
contents of sourceCollection, if it’s present."""
self.items = None
self.size = 0
if sourceCollection:
for item in sourceCollection:
self.add(item)Iterator__iter__ method for LinkedBag supports the same kind of traversal as it does in ArrayBag:
clear and addclear in LinkedBag is quite similar to its sister method in ArrayBagadd in LinkedBag leverages constant-time access by placing the new item at the head of the linked structureremove Methodremove in LinkedBag must first handle the precondition and then do a sequential search for the target itemelf.items to this node’s next linkremove Methoddef remove(self, item):
"""Precondition: item is in self.
Raises: KeyError if item is not in self.
Postcondition: item is removed from self."""
# Check precondition and raise an exception if necessary
if not item in self:
raise KeyError(str(item) + " not in bag")
# Search for the node containing the target item
# probe will point to the target node, and trailer
# will point to the node before it, if it exists
probe = self.items
trailer = None
for targetItem in self:
if targetItem == item:
break
trailer = probe
probe = probe.next
# Unhook the node to be deleted, either the first one or
# one thereafter
if probe == self.items:
self.items = self.items.next
else:
trailer.next = probe.next
# Decrement logical size
self.size -= 1
in and remove operations take linear time in both implementations, because they incorporate a sequential searchremove operation in ArrayBag must do the additional work of shifting data items in the array, but the cumulative effect is not worse than linear+, str, and iter operations are linear== operation has several cases and is left as an exerciseArrayBag’s add incurs an occasional linear time hit to resize the arrayArrayBag is better than half full,
LinkedBag of the same logical sizeLinkedBag uses twice as much memory as an ArrayBag whose array is fullArrayBag are generally slower than they are on a LinkedBag"""
File: testbag.py
A tester program for bag implementations.
"""
from arraybag import ArrayBag
from linkedbag import LinkedBag
def test(bagType):
"""Expects a bag type as an argument and runs some tests
on objects of that type."""
print("Testing", bagType)
lyst = [2013, 61, 1973]
print("The list of items added is:", lyst)
b1 = bagType(lyst)
print("Length, expect 3:", len(b1))
print("Expect the bag’s string:", b1)
print("2013 in bag, expect True:", 2013 in b1)
print("2012 in bag, expect False:", 2012 in b1)
print("Expect the items on separate lines:")
for item in b1:
print(item)
b1.clear()
print("Clearing the bag, expect {}:", b1)
b1.add(25)
b1.remove(25)
print("Adding and then removing 25, expect {}:", b1)
b1 = bagType(lyst)
b2 = bagType(b1)
print("Cloning the bag, expect True for ==:", b1 == b2)
print("Expect False for is:", b1 is b2)
print("+ the two bags, expect two of each item:", b1 + b2)
for item in lyst:
b1.remove(item)
print("Remove all items, expect {}:", b1)
print("Removing nonexistent item, expect crash with KeyError:")
b2.remove(99)
ArraySortedBag (Project 3 of Chapter 5)
ArrayBag, but with exceptions:in operator runs in logarithmic timeArraySortedBag class a subclass of the ArrayBag class:
ArrayBag is called the parent or superclass of ArraySortedBagArrayBag class implements BagInterface, the ArraySortedBag class also implements this interface via inheritanceThis diagram depicts a subclass and inheritance in a class diagram
_init_ method in the new class_init_ method in ArraySortedBag must call the _init_ method in the parent class ArrayBag
ArrayBag._init_(self, sourceCollection)_init_ method to run_init_ methodfrom arraybag import ArrayBag
class ArraySortedBag(ArrayBag):
"""An array-based sorted bag implementation."""
# Constructor
def __init__(self, sourceCollection = None):
"""Sets the initial state of self, which includes the
contents of sourceCollection, if it’s present."""
ArrayBag.__init__(self, sourceCollection)_contains_ Method
_contains_ method in ArrayBag: Python automatically generates a sequential search operation, using the ArrayBag iterator, when the in operator is used on a bag_contains_ method in ArraySortedBag:
in operator used on a sorted bag, it also sees that bag’s _contains_ method and calls itself.items is accessible in any of its subclasses_contains_ Method# Accessor methods
def __contains__(self, item):
"""Returns True if item is in self, or False otherwise."""
left = 0
right = len(self) - 1
while left <= right:
midPoint = (left + right) // 2
if self.items[midPoint] == item:
return True
elif self.items[midPoint] > item:
right = midPoint - 1
else:
left = midPoint + 1
return Falseadd Methodadd method in ArraySortedBag must place a new item in the appropriate position in a sorted arrayArrayBag classadd Method# Mutator methods
def add(self, item):
"""Adds item to self."""
# Empty or last item, call ArrayBag.add
if self.isEmpty() or item >= self.items[len(self) - 1]:
ArrayBag.add(self, item)
else:
# Resize the array if it is full here
# Search for first item >= new item
targetIndex = 0
while item > self.items[targetIndex]:
targetIndex += 1
# Open a hole for new item
for i in range(len(self), targetIndex, -1):
self.items[i] = self.items[i - 1]
# Insert item and update size
self.items[targetIndex] = item
self.size += 1
add MethodArrayBag.add and in the variable reference to self.items:
ArraySortedBag does not introduce a new version of the instance variable items, the reference to self.items here locates the variable directly in the ArrayBag class._add_ Method__add__ method, which Python runs when it sees the + operator used with two bags, has practically the same code in the ArrayBag class and the LinkedBag class:name used to create a new instance for the result bag__add__ in ArraySortedBag, as follows:in operator has a worst-case running time of O(logn):
in operator,
ArrayBagremove with a linear running time on average,
ArraySortedBag which inherits the ArrayBag class.ArraySortedBag.