Download Abstract Data Types: Stacks, Queues, and Memory Management and more Thesis Data Structures and Algorithms in PDF only on Docsity!
ASSIGNMENT FINAL REPORT
Qualification Pearson BTEC Level 5 Higher National Diploma in Computing Unit number and title Unit 19: Data Structures and Algorithms Submission date Date Received 1st submission Re-submission Date Date Received 2nd submission Student Name Student ID Class Assessor name
Plagiarism
Plagiarism is a particular form of cheating. Plagiarism must be avoided at all costs and students who break the rules, however innocently, may be penalised. It is your responsibility to ensure that you understand correct referencing practices. As a university level student, you are expected to use appropriate references throughout and keep carefully detailed notes of all your sources of materials for material you have used in your work, including any material downloaded from the Internet. Please consult the relevant unit lecturer or your course tutor if you need any further advice.
Student Declaration
I certify that the assignment submission is entirely my own work and I fully understand the consequences of plagiarism. I declare that the work submitted for assessment has been carried out without assistance other than that which is acceptable according to the rules of the specification. I certify I have clearly referenced any sources and any artificial intelligence (AI) tools used in the work. I understand that making a false declaration is a form of malpractice. Student’s signature Grading grid
- P1 P2 P3 P4 P5 P6 P7 M1 M2 M3 M4 M5 D1 D2 D3 D
A. INTRODUCTION In the fast-evolving world of software development, leveraging abstract data types (ADTs) has become fundamental in creating robust, maintainable, and scalable applications. For Soft Development ABK, a studio focused on delivering software solutions for small and medium-sized enterprises, ADTs serve as essential tools to standardize our design, streamline development, and strengthen rigorous testing practices. This presentation aims to demonstrate how implementing abstract data types in our workflows can elevate our project efficiency and product reliability. Abstract data types, by definition, provide a formal method to encapsulate data and operations, serving as a blueprint for building complex data structures while hiding implementation details. In this presentation, we will explore the role of ADTs in improving the design architecture, promoting code reuse, and simplifying debugging processes. Additionally, I will outline the benefits of utilizing formal algorithms and notations to express these types, ensuring consistency and accuracy across our codebase.
B. CONTENTS I.(P1) Create a design specification for data structures, explaining the valid operations that can be carried out on the structures Data structure design is an important phase in software development. It determines the efficiency of accessing, processing, storing and transmitting data throughout the system. Whether it is a small application or a large system, a well-designed data structure will directly affect the performance, scalability and maintainability of the software. Without a clear structure, even the most optimal algorithms can become inefficient and complex. In modern software development, ADTs (Abstract Data Types) act as blueprints for organizing and managing data. ADTs describe the valid operations
Figure 1: Stack
Operations on Stacks:
- push(): is an operation that inserts elements into the stack
- pop(): is a data manipulation operation which removes elements from the stack
- peek(): is an operation retrieves the topmost element within the stack, without deleting it.
- isFull() operation checks whether the stack is full
- isEmpty() operation verifies whether the stack is empty. Application:
- Function call management: The stack stores information about function calls and parameters when a function is called.
- Parentheses checking: The stack checks the validity of parentheses in mathematical expressions or source code.
- Undo/Redo: The stack stores operations to support undo and redo in office applications. Example:
Figure 2: Implement Stack
Figure 3: Result of Stack
b. Queue
Figure 5: Implement Queue
Figure 6: Result of Queue
c. Linked List
A linked list is a linear data structure which can store a collection of "nodes" connected together via links i.e. pointers. Linked lists nodes are not stored at a contiguous location, rather they are linked using pointers to the different memory locations. A node consists of the data value and a pointer to the address of the next node within the linked list.
Figure 7: Link list
Operations on Link List:
- Insertion: Adds an element at the beginning of the list.
- Deletion: Deletes an element at the beginning of the list.
- Display: Displays the complete list.
- Search: Searches an element using the given key.
- Delete: Deletes an element using the given key. Application:
- Storing data sequences: Lists are used to store elements in order.
- Linked lists: Often used when the size of the list is unknown and needs to change dynamically.
- Managing data in order: Applications that need data to be stored in a certain order, such as a list of calls or a list of tasks to be performed.
- Editing data: When you need to add, edit, or delete elements flexibly and quickly. Example:
In data structures, Stack and Queue are two essential and widely used abstract data types for managing, organizing, and processing data efficiently. This section analyzes their operational complexity and highlights typical use cases where they are preferred due to their performance characteristics. a. Stack A stack is a linear data structure that follows the LIFO (Last In, First Out) principle. This means the last element pushed onto the stack will be the first to be popped. Complexity:
- push() – O(1): Adds an element to the top of the stack
- pop() – O(1): Removes and returns the top element
- peek() – O(1): Returns the top element without removing it Applications:
- Function Call Management: Programming languages use stacks to manage function calls and return points (call stack)
- Expression Evaluation & Syntax Parsing: Used in arithmetic expression evaluation and compiler design for parsing expressions.
- Backtracking Algorithms: Algorithms like Depth-First Search (DFS) and maze solving use stacks to remember previous states.
- Undo/Redo Operations: Many text editors and graphic programs use stacks to implement undo and redo functionalities. b. Queue A queue is a linear data structure that follows the FIFO (First In, First Out) principle. The first element added to the queue is the first one to be removed. Complexity:
- enqueue() – O(1): Adds an element to the rear of the queue
- dequeue() – O(1): Removes and returns the front element
- peek() – O(1): Returns the front element without removing it Applications:
- Task Scheduling: Used in operating systems to manage processes in task scheduling algorithms
- Print Queue Management: Print jobs are processed in the order they are received
- Breadth-First Search (BFS): Used in graph algorithms for level-order traversal
- Network Communication: Manages packets in routers and switches c. Linked List
A linked list is a dynamic structure composed of nodes where each node contains data and a reference (pointer) to the next node. Complexity:
- insertAtBeginning() – O(1)
- insertAtEnd() – O(n)
- delete() – O(n)
- search() – O(n) Applications:
- Dynamic Memory Usage: Suitable for cases where the number of elements is unknown and changes frequently
- Implementing Other Data Structures: Often used to implement stacks, queues, hash tables, and adjacency lists
- Music or Video Playlists: Where next and previous navigation is required (doubly linked list) **P2. Determine the operations of a memory stack and how it is used to implement function calls in a computer.
- Memory Stack Overview** The memory stack is an important data structure in a computer system, playing a decisive role in managing memory when performing function calls. The stack operates under the LIFO (Last In, First Out) principle, which means that the last element added will be the first to be removed. This principle not only helps the program handle functions efficiently, but also protects memory stability throughout execution. Stack Structure and Operation The memory stack uses the LIFO principle to temporarily manage memory during program execution. When a function is called, a new stack frame is created and pushed onto the top of the stack. This stack frame contains all the necessary information for the function, including:
- Parameters passed to the function
- Local variables declared inside the function
- Return address to resume the program after the function completes Once the function completes execution, the stack frame is popped from the stack, and control returns to the calling function. This allows each function call to be handled separately and efficiently without overlapping memory use.
- When C() completes, its frame is popped off the stack
- Control returns to B(), which continues its execution until it ends and is also popped
- The process continues until the stack unwinds completely back to the main() function Example:
Figure 10: Example of Function call management process
Explain: Step 1: When calling A()
- A() start: The stack frame for A() is created, with the variable x = 3 Step 2: A() calls B(x)
- B() is called, and a new stack frame for B() is created
- num = 3 (parameter transmitted from A()) and y = num + 2 = 5 are stored in the stack frame of B() Step 3: B() completes
- After B() executes (printing out the value of y), the stack frame of B() is discarded
- The program returns to A() to continue executing the System.out.println("End of A") 3. Stack and Regression The memory stack plays an important role in memory management when performing function calls, especially in the case of recursive functions. Regression is the process of a function calling itself during execution, and to manage these calls, the system uses a memory stack. Each recursive call
creates a new stack frame, and the local parameters, variables at each regression level are stored separately. The memory stack helps track the levels of regression, ensures that the data of different calls are not mixed, and manages the return process from the levels of regression. Roles of Stack in Regression In recursive algorithms, the stack is essential for maintaining the order of function calls and preserving intermediate data. Since the stack operates on the Last-In-First-Out (LIFO) principle, the most recent function call is the first one to finish and return. When a recursive function is invoked:
- A stack frame is created for the call, holding its unique parameters, local variables, and the return address.
- This frame is then pushed onto the top of the stack.
- Once the function finishes, the frame is popped off the stack, and control resumes from the point where the call was originally made. Recursive example: Fibonacci Number
Figure 11: Example Fibonacci Number
Call fibonacci(4)
- Create stack frame for fibonacci(4)
- Calls fibonacci(3) Call fibonacci(3)
- Create stack frame for fibonacci(3)
- Calls fibonacci(2) Call fibonacci(2)
- Create stack frame for fibonacci(2)
- The memory allocated for the stack is limited. Programs with deep recursion or large data per function call can quickly exhaust the stack space, causing errors. This poses challenges in applications that involve large computations or complex recursive logic. **P3. Specify the abstract data type for a software stack using an imperative definition.
- Overview of Abstract Data Type (ADT) and Command-Based Definition** An Abstract Data Type (ADT) is a conceptual model used to describe how data is organized and what operations can be performed on it, without specifying how the operations are implemented. ADTs focus on the functionality offered to the user rather than the details of internal storage or algorithms. Users interact with the ADT through a defined set of operations, regardless of how the underlying structure is constructed or maintained. The command-based definition (or imperative approach) refers to a method of defining ADTs by specifying exact, step-by-step instructions for each operation. This method describes how each operation processes input, changes the internal state, and produces output. The key strength of this approach lies in its explicit nature, where the logic of each operation is broken down into concrete actions or computer- like commands, making it suitable for direct implementation in programming languages. Instead of keeping the definition abstract, the command approach explains how each operation is carried out in practice. 2. Example of defining Stack ADT Using Command-Based Approach Below is an example of how the Stack ADT can be defined using the imperative (command-based) approach: push(x)
- Input: Element x to be pushed onto the stack
- Output: Updated stack with x added at the top
- Action: Place x at the current top index of the stack and increase the top pointer by one pop()
- Input: None
- Output: The element that was at the top of the stack
- Action: Retrieve the element at the current top, remove it from the stack, and decrease the top pointer by one peek()
- Input: None
- Output: The element at the top of the stack
- Action: Return the current top element without modifying the stack isEmpty()
- Input: None
- Output: Returns true if the stack contains no elements, otherwise false
- Action: Check whether the top pointer indicates that the stack is empty 3. Implementing ADT Stack example in Java