What is a List?
Đặng Đình Sáng
Posted on June 25, 2024
Lists are an abstract data structure that can be implemented using linked lists or arrays.
Linked lists inherently support list operations and can dynamically adjust their size, while arrays have a fixed length, making them less practical for use as lists. To address the limitations of arrays, lists can be implemented using dynamic arrays that can expand as needed during program execution. Dynamic arrays inherit the advantages of arrays while providing the flexibility to grow and shrink as the program requires. The choice between linked lists and dynamic arrays for implementing lists depends on the specific requirements and trade-offs of the application.
Common list operations
- Initializing
# Without initial values
nums1: list[int] = []
# With initial values
nums: list[int] = [1, 3, 2, 5, 4]
- Accessing elements
Access and update elements in O(1) time
# Access elements
num: int = nums[1] # Access the element at index 1
# Update elements
nums[1] = 0 # Update the element at index 1 to 0
- Inserting and Removing
Adding elements to the end of a list is an O(1) operation, the efficiency of inserting and removing elements elsewhere in the list remains the same as in arrays, with a time complexity of O(n)
nums.clear()
# Append elements at the end
nums.append(1)
nums.append(3)
nums.append(2)
nums.append(5)
nums.append(4)
nums.insert(3, 6) # Insert number 6 at index 3
nums.pop(3) # Remove the element at index 3
- Iterating the list
# Iterate through the list by index
count = 0
for i in range(len(nums)):
count += nums[i]
# Iterate directly through list elements
for num in nums:
count += num
- Concatenating
nums1: list[int] = [6, 8, 7, 10, 9]
nums += nums1 # Concatenate nums1 to the end of nums
- Sorting
nums.sort()
List implementation
To understand how lists work, we'll implement a simplified version focusing on three key design aspects:
- Initial Capacity: Start with an array of size 10.
- Size Recording: Keep a variable size to track the current number of elements, updating it with each insertion or deletion.
- Expansion Mechanism: When the array reaches capacity, double its size and transfer all elements to the new array. This approach helps manage dynamic arrays efficiently by balancing memory usage and performance.
class MyList:
"""List class"""
def __init__(self):
"""Constructor"""
self._capacity: int = 10 # List capacity
self._arr: list[int] = [0] * self._capacity # Array (stores list elements)
self._size: int = 0 # List length (current number of elements)
self._extend_ratio: int = 2 # Multiple for each list expansion
def size(self) -> int:
"""Get list length (current number of elements)"""
return self._size
def capacity(self) -> int:
"""Get list capacity"""
return self._capacity
def get(self, index: int) -> int:
"""Access element"""
# If the index is out of bounds, throw an exception, as below
if index < 0 or index >= self._size:
raise IndexError("Index out of bounds")
return self._arr[index]
def set(self, num: int, index: int):
"""Update element"""
if index < 0 or index >= self._size:
raise IndexError("Index out of bounds")
self._arr[index] = num
def add(self, num: int):
"""Add element at the end"""
# When the number of elements exceeds capacity, trigger the expansion mechanism
if self.size() == self.capacity():
self.extend_capacity()
self._arr[self._size] = num
self._size += 1
def insert(self, num: int, index: int):
"""Insert element in the middle"""
if index < 0 or index >= self._size:
raise IndexError("Index out of bounds")
# When the number of elements exceeds capacity, trigger the expansion mechanism
if self._size == self.capacity():
self.extend_capacity()
# Move all elements after `index` one position backward
for j in range(self._size - 1, index - 1, -1):
self._arr[j + 1] = self._arr[j]
self._arr[index] = num
# Update the number of elements
self._size += 1
def remove(self, index: int) -> int:
"""Remove element"""
if index < 0 or index >= self._size:
raise IndexError("Index out of bounds")
num = self._arr[index]
# Move all elements after `index` one position forward
for j in range(index, self._size - 1):
self._arr[j] = self._arr[j + 1]
# Update the number of elements
self._size -= 1
# Return the removed element
return num
def extend_capacity(self):
"""Extend list"""
# Create a new array of _extend_ratio times the length of the original array and copy the original array to the new array
self._arr = self._arr + [0] * self.capacity() * (self._extend_ratio - 1)
# Update list capacity
self._capacity = len(self._arr)
def to_array(self) -> list[int]:
"""Return a list of valid lengths"""
return self._arr[: self._size]
Reference
Posted on June 25, 2024
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.