Gap Buffer Data Structure
INTRODUCTION:
Gap Buffer is a data structure for the dynamic insertion and deletion of elements in a buffer or an array. It represents a buffer or an array as a gap surrounded by two pointers, one pointing to the beginning of the buffer and the other pointing to the end. When elements are inserted or deleted, the gap is moved to accommodate the change, instead of resizing the entire buffer.
Gap Buffer is designed to be an efficient data structure for real-time applications, such as text editors and code editors, where fast and dynamic insertion and deletion of elements are important. The gap buffer data structure provides an average time complexity of O(1) for inserting elements at the current cursor position, making it a suitable choice for applications that require low latency.
In addition to its efficiency and real-time capabilities, Gap Buffer is also a space-efficient data structure, as it uses a gap to represent empty space in the buffer, minimizing the number of memory reallocations required for insertions and deletions. The Gap Buffer data structure is relatively simple to implement, making it a popular choice for a wide range of applications.
Gap Buffer is a data structure used for editing and storing text in an efficient manner that is being currently edited. It is also similar to an array but a gap is introduced in the array for handling multiple changes at the cursor. Let’s assume a gap to be another array that contains empty spaces.
Example: Consider an example with initial gap size 10, initially, array or gap are of the same size, as we insert the elements in the array similarly elements will be inserted in the gap buffer, the only difference is gap size reduces on each insert.
This was the basic case to insert the character in the front. Now, whenever there is need to insert a character at certain position we will just move the gap up-to that position using left() and right() then try to insert the character.
Need for Gap Buffer
- Array is a data structure which stores items at contiguous memory location. However, it takes O(1) insertion at end of the array while O(n) time in front because the array will be shifted n places right, n being the length of the array.
- When it comes to text editors we need a faster data structure for insertion, modification as there are multiple changes at the cursor positions.
- In worst case array will take O(n) time for insertion or modification as shown in the example below.
- For inserting ‘GEEKS’ at the front, space is made for inserting each character by shifting the array.
Basic operations in Gap Buffer
- insert(): It is a procedure used to insert character into the text at a given position. It first checks whether the gap is empty or not, if it finds that the gap is empty it calls procedure grow() and resizes the gap and now the element can be inserted.
- left() : It is a procedure used for moving the cursor to left and this cursor point is used as position for changes.
right: It is a procedure used for moving the cursor to right and this cursor point is used as position for changes.- grow: It is a procedure used when the gap size has become zero and therefore we need to resize the array by inserting a gap at desired position.
Gap Buffer vs Ropes
Now, although its insertion is taking O(1) time but there is another function grow() which takes approximately O(n) time. So there might a thought that this may take the same time as the rope data structures but the cost of grow is being compensated by amortized cost of other cheaper procedures such as left(), right() and insert(). Therefore this data structure get preferences in text-editors over other such as rope as it is easy to implement.
Implementing Gap Buffer
C++
// C++ program of implementation of gap buffer #include <bits/stdc++.h> using namespace std; char buffer[50]; int gap_size = 10; int gap_left = 0; int gap_right = gap_size - gap_left-1; int size = 10; // Function that is used to grow the gap // at index position and return the array void grow( int k, int position) { char a[size]; // Copy characters of buffer to a[] // after position for ( int i = position; i < size; i++) { a[i - position] = buffer[i]; } // Insert a gap of k from index position // gap is being represented by '-' for ( int i = 0; i < k; i++) { buffer[i + position] = '_' ; } // Reinsert the remaining array for ( int i = 0; i < position + k; i++) { buffer[position + k + i] = a[i]; } size += k; gap_right+=k; } // Function that is used to move the gap // left in the array void left( int position) { // Move the gap left character by character // and the buffers while (position < gap_left) { gap_left--; gap_right--; buffer[gap_right+1] = buffer[gap_left]; buffer[gap_left]= '_' ; } } // Function that is used to move the gap // right in the array void right( int position) { // Move the gap right character by character // and the buffers while (position > gap_left) { gap_left++; gap_right++; buffer[gap_left-1] = buffer[gap_right]; buffer[gap_right]= '_' ; } } // Function to control the movement of gap // by checking its position to the point of // insertion void move_cursor( int position) { if (position < gap_left) { left(position); } else { right(position); } } // Function to insert the string to the buffer // at point position void insert(string input, int position) { int len = input.length(); int i = 0; // If the point is not the gap check // and move the cursor to that point if (position != gap_left) { move_cursor(position); } // Insert characters one by one while (i < len) { // If the gap is empty grow the size if (gap_right == gap_left) { int k = 10; grow(k, position); } // Insert the character in the gap and // move the gap buffer[gap_left] = input[i]; gap_left++; i++; position++; } } // Driver code int main() { // Initializing the gap buffer with size 10 for ( int i = 0; i < 10; i++) { buffer[i] = '_' ; } cout << "Initializing the gap buffer " << "with size 10" << endl; for ( int i = 0; i < size; i++) { cout << buffer[i]<< " " ; } cout << endl; // Inserting a string to buffer string input = "GEEKSGEEKS" ; int position = 0; insert(input, position); cout << endl; cout << "Inserting a string to buffer" << ": GEEKSGEEKS" << endl; cout << "Output: " ; for ( int i = 0; i < size; i++) { cout << buffer[i]<< " " ; } input = "FOR" ; position = 5; insert(input, position); cout << endl; cout << endl; cout << "Inserting a string to buffer" << ": FOR" << endl; cout << "Output: " ; for ( int i = 0; i < size; i++) { cout << buffer[i]<< " " ; } return 0; } |
Java
// Java program of implementation of gap buffer import java.util.*; class GFG { static char []buffer = new char [ 50 ]; static int gap_size = 10 ; static int gap_left = 0 ; static int gap_right = gap_size - gap_left - 1 ; static int size = 10 ; // Function that is used to grow the gap // at index position and return the array static void grow( int k, int position) { char []a = new char [size]; // Copy characters of buffer to a[] // after position for ( int i = position; i < size; i++) { a[i - position] = buffer[i]; } // Insert a gap of k from index position // gap is being represented by '-' for ( int i = 0 ; i < k; i++) { buffer[i + position] = '_' ; } // Reinsert the remaining array for ( int i = 0 ; i < k; i++) { buffer[position + k + i] = a[i]; } size += k; gap_right += k; } // Function that is used to move the gap // left in the array static void left( int position) { // Move the gap left character by character // and the buffers while (position < gap_left) { gap_left--; gap_right--; buffer[gap_right + 1 ] = buffer[gap_left]; buffer[gap_left]= '_' ; } } // Function that is used to move the gap // right in the array static void right( int position) { // Move the gap right character by character // and the buffers while (position > gap_left) { gap_left++; gap_right++; buffer[gap_left - 1 ] = buffer[gap_right]; buffer[gap_right]= '_' ; } } // Function to control the movement of gap // by checking its position to the point of // insertion static void move_cursor( int position) { if (position < gap_left) { left(position); } else { right(position); } } // Function to insert the string to the buffer // at point position static void insert(String input, int position) { int len = input.length(); int i = 0 ; // If the point is not the gap check // and move the cursor to that point if (position != gap_left) { move_cursor(position); } // Insert characters one by one while (i < len) { // If the gap is empty grow the size if (gap_right == gap_left) { int k = 10 ; grow(k, position); } // Insert the character in the gap and // move the gap buffer[gap_left] = input.charAt(i); gap_left++; i++; position++; } } // Driver code public static void main(String[] args) { // Initializing the gap buffer with size 10 for ( int i = 0 ; i < 10 ; i++) { buffer[i] = '_' ; } System.out.println( "Initializing the gap" + " buffer with size 10" ); for ( int i = 0 ; i < size; i++) { System.out.print(buffer[i] + " " ); } System.out.println(); // Inserting a string to buffer String input = "GEEKSGEEKS" ; int position = 0 ; insert(input, position); System.out.println(); System.out.println( "Inserting a string " + "to buffer: GEEKSGEEKS" ); System.out.print( "Output: " ); for ( int i = 0 ; i < size; i++) { System.out.print(buffer[i] + " " ); } input = "FOR" ; position = 5 ; insert(input, position); System.out.println(); System.out.println(); System.out.println( "Inserting a string" + " to buffer: FOR" ); System.out.print( "Output: " ); for ( int i = 0 ; i < size; i++) { System.out.print(buffer[i] + " " ); } } } // This code is contributed by Princi Singh |
Python3
# Python program of implementation of gap buffer buffer = [ '_' for i in range ( 50 )] gap_size = 10 gap_left = 0 gap_right = gap_size - gap_left - 1 size = 10 # Function that is used to grow the gap # at index position and return the array def grow(k, position): global size, gap_right, gap_left, buffer a = buffer [position:size] # Insert a gap of k from index position # gap is being represented by '-' buffer [position:position + k] = [ '_' for i in range (k)] # Reinsert the remaining array buffer [position + k:position + k + size - position] = a size + = k gap_right + = k # Function that is used to move the gap # left in the array def left(position): global gap_left, gap_right, buffer # Move the gap left character by character # and the buffers while position < gap_left: gap_left - = 1 gap_right - = 1 buffer [gap_right + 1 ] = buffer [gap_left] buffer [gap_left] = '_' # Function that is used to move the gap # right in the array def right(position): global gap_left, gap_right, buffer # Move the gap right character by character # and the buffers while position > gap_left: gap_left + = 1 gap_right + = 1 buffer [gap_left - 1 ] = buffer [gap_right] buffer [gap_right] = '_' # Function to control the movement of gap # by checking its position to the point of # insertion def move_cursor(position): if position < gap_left: left(position) else : right(position) # Function to insert the string to the buffer # at point position def insert( input , position): global gap_left, gap_right len_input = len ( input ) i = 0 # If the point is not the gap check # and move the cursor to that point if position ! = gap_left: move_cursor(position) # Insert characters one by one while i < len_input: # If the gap is empty grow the size if gap_right = = gap_left: k = 10 grow(k, position) # Insert the character in the gap and # move the gap buffer [gap_left] = input [i] gap_left + = 1 i + = 1 position + = 1 # Initializing the gap buffer with size 10 for i in range ( 10 ): buffer [i] = '_' print ( "Initializing the gap buffer with size 10" ) print ( buffer [:size]) # Inserting a string to buffer input_str = "GEEKSGEEKS" position = 0 insert(input_str, position) print ( "Inserting a string to buffer: GEEKSGEEKS" ) print ( "Output:" , buffer [:size]) input_str = "FOR" position = 5 insert(input_str, position) print ( "\n" ) print ( "\n" ) print ( "Inserting a string to buffer: FOR" ) print ( "Output: " , end = "") for i in range (size): print ( buffer [i], end = " " ) |
C#
// C# program of implementation of gap buffer using System; class GFG { static char []buffer = new char [50]; static int gap_size = 10; static int gap_left = 0; static int gap_right = gap_size - gap_left - 1; static int size = 10; // Function that is used to grow the gap // at index position and return the array static void grow( int k, int position) { char []a = new char [size]; // Copy characters of buffer to a[] // after position for ( int i = position; i < size; i++) { a[i - position] = buffer[i]; } // Insert a gap of k from index position // gap is being represented by '-' for ( int i = 0; i < k; i++) { buffer[i + position] = '_' ; } // Reinsert the remaining array for ( int i = 0; i < k; i++) { buffer[position + k + i] = a[i]; } size += k; gap_right += k; } // Function that is used to move the gap // left in the array static void left( int position) { // Move the gap left character by character // and the buffers while (position < gap_left) { gap_left--; gap_right--; buffer[gap_right + 1] = buffer[gap_left]; buffer[gap_left]= '_' ; } } // Function that is used to move the gap // right in the array static void right( int position) { // Move the gap right character by character // and the buffers while (position > gap_left) { gap_left++; gap_right++; buffer[gap_left - 1] = buffer[gap_right]; buffer[gap_right] = '_' ; } } // Function to control the movement of gap // by checking its position to the point of // insertion static void move_cursor( int position) { if (position < gap_left) { left(position); } else { right(position); } } // Function to insert the string to the buffer // at point position static void insert(String input, int position) { int len = input.Length; int i = 0; // If the point is not the gap check // and move the cursor to that point if (position != gap_left) { move_cursor(position); } // Insert characters one by one while (i < len) { // If the gap is empty grow the size if (gap_right == gap_left) { int k = 10; grow(k, position); } // Insert the character in the gap and // move the gap buffer[gap_left] = input[i]; gap_left++; i++; position++; } } // Driver code public static void Main(String[] args) { // Initializing the gap buffer with size 10 for ( int i = 0; i < 10; i++) { buffer[i] = '_' ; } Console.WriteLine( "Initializing the gap" + " buffer with size 10" ); for ( int i = 0; i < size; i++) { Console.Write(buffer[i] + " " ); } Console.WriteLine(); // Inserting a string to buffer String input = "GEEKSGEEKS" ; int position = 0; insert(input, position); Console.WriteLine(); Console.WriteLine( "Inserting a string " + "to buffer: GEEKSGEEKS" ); Console.Write( "Output: " ); for ( int i = 0; i < size; i++) { Console.Write(buffer[i] + " " ); } input = "FOR" ; position = 5; insert(input, position); Console.WriteLine(); Console.WriteLine(); Console.WriteLine( "Inserting a string" + " to buffer: FOR" ); Console.Write( "Output: " ); for ( int i = 0; i < size; i++) { Console.Write(buffer[i] + " " ); } } } // This code is contributed by 29AjayKumar |
Javascript
let buffer = new Array(50).fill( '_' ); let gap_size = 10; let gap_left = 0; let gap_right = gap_size - gap_left - 1; let size = 10; // Function that is used to grow the gap // at index position and return the array function grow(k, position) { let a = buffer.slice(position, size); // Copy characters of buffer to a[] // after position buffer.splice(position, size - position, ...( '_' .repeat(k))); // Insert a gap of k from index position // gap is being represented by '-' // Reinsert the remaining array buffer.splice(position + k, 0, ...a); size += k; gap_right += k; } // Function that is used to move the gap // left in the array function left(position) { // Move the gap left character by character // and the buffers while (position < gap_left) { gap_left--; gap_right--; buffer[gap_right + 1] = buffer[gap_left]; buffer[gap_left] = '_' ; } } // Function that is used to move the gap // right in the array function right(position) { // Move the gap right character by character // and the buffers while (position > gap_left) { gap_left++; gap_right++; buffer[gap_left - 1] = buffer[gap_right]; buffer[gap_right] = '_' ; } } // Function to control the movement of gap // by checking its position to the point of // insertion function move_cursor(position) { if (position < gap_left) { left(position); } else { right(position); } } // Function to insert the string to the buffer // at point position function insert(input, position) { let len = input.length; let i = 0; // If the point is not the gap check // and move the cursor to that point if (position !== gap_left) { move_cursor(position); } // Insert characters one by one while (i < len) { // If the gap is empty grow the size if (gap_right === gap_left) { let k = 10; grow(k, position); } // Insert the character in the gap and // move the gap buffer[gap_left] = input.charAt(i); gap_left++; i++; position++; } } let temp = "" ; for (let i = 0; i < size; i++) { temp+=(buffer[i] + " " ); } console.log( "Initializing the gap buffer with size 10" ); console.log(temp); // Inserting a string to buffer let input = "GEEKSGEEKS" ; let position = 0; insert(input, position); console.log(); console.log( "Inserting a string to buffer: GEEKSGEEKS" ); console.log( "Output: " + buffer.join( ' ' )); input = "FOR" ; position = 5; insert(input, position); console.log(); console.log( "Inserting a string to buffer: FOR" ); console.log( "Output: " + buffer.join( ' ' )); |
Initializing the gap buffer with size 10 _ _ _ _ _ _ _ _ _ _ Inserting a string to buffer: GEEKSGEEKS Output: G E E K S G E E K S _ _ _ _ _ _ _ _ _ _ Inserting a string to buffer: FOR Output: G E E K S F O R _ _ _ _ _ _ _ G E E K S
Time complexity of insert: O(1) Time complexity of grow: O(n)
Advantages: Gap Buffer Data Structure:
Advantages of Gap Buffer Data Structure:
- Dynamic: Gap Buffer data structure allows for dynamic insertions and deletions of elements, making it suitable for changing datasets.
- Efficient: Gap Buffer has an efficient time complexity for insertions and deletions, with an average time complexity of O(1) for inserting elements at the current cursor position.
- Space-efficient: Gap Buffer is a space-efficient data structure that uses a gap to represent empty space in the buffer, minimizing the number of memory reallocations required for insertions and deletions.
- Easy to implement: Gap Buffer is relatively simple to implement, making it a popular choice for text editors and other applications that require dynamic insertion and deletion of elements.
- Suitable for real-time: Gap Buffer is designed for real-time use, making it suitable for applications where low latency and fast insertions and deletions are important.
- Versatile: Gap Buffer can be used for a wide range of applications, including text editors, code editors, and other applications that require dynamic insertion and deletion of elements.
Please Login to comment...