Data_Structures_and_Algorithms_in_ABAP_1691932213
Data_Structures_and_Algorithms_in_ABAP_1691932213
Also other programming language developers use the abbreviation DSA. What
actually is DSA? It is nothing but the title of this series, Data Structure and
Algorithm. If you visit leetcode or geekforgeeks you would find tons and tons of
contents on DSA. Java, Python, JavaScript etc has been using DSA from ages and
DSA is one of the core questions in interviews and selections process. In ABAP
also, we have DSA but we ABAP Developers do not use those Fancy terminologies.
We would rather try to understand the clients business and find the solution. After
all ABAP is Business Application Programming.
Really, strings and internal tables are DSAs. Why should non-ABAP
developers have all the fun?
In this blog series, we will see the usage of the above data structures to
solve some problems using known algorithms and sometimes, we will
implement our own algorithm by using some widely known problem solving
techniques.
Problem: Given an array of integers of size ‘n’, find the
maximum sum of ‘k’ consecuCve elements in the array.
Input : arr[ ] = { 5, 1, 2, 6, 4, 3 } , k = 2
Output: 10
If you appear interview of FAANG companies (oops, these days it is MAANG, M for
Meta and not Microsoft ), you might not get SAP Business related problem
solving. You might be asked questions like above. Or may be find the prime
numbers. Seriously..
Let’s see how many Iterations will be needed to loop through all elements in the
input array.
We can observe that all Iterations for outer loop would not be required but It can
be derived by simple observation by considering the no. of places for consecutive
elements in the problem statement.
No. of Iterations required : N + 1 – K
N : size of array
K : no. of consecutive elements
OpCmized Approach:
This problem can be optimized using the famous sliding window technique.
Now we are also getting fancy.
Similarly, now once again we slide our window by a unit index and obtain the new
window sum to be 8. Again we check if this current window sum is greater than
the maximum_sum till now. Since it is greater, we will change the maximum_sum
with current_sum i.e. 8.
Now once again we slide our window by a unit index and obtain the new window
sum to be
10. Again we check if this current window sum is greater than the
maximum_sum till now. Since it is greater, we will change the maximum_sum
with current_sum i.e. 10.
Similarly, now once again we slide our window by a unit index and obtain the new
window sum to be 7. Again we check if this current window sum is greater than
the maximum_sum till now. As it is smaller so we don’t change the
maximum_sum.
Since we reach the end of the elements, we will stop searching for maximum sum
and assign the calculated maximum_sum to output.
No. of Iterations required : N – K
N : size of array
K : no. of consecutive elements
1. Outer Loop through all the elements starting from the 1st index.
2. Inner loop through all the elements starting from the next index till end of
array .
3. Calculate the sum and check if it’s equal to the target. If yes, append the
index from outer and inner loops in the result table and EXIT.
As we have seen that after all inner iterations, we couldn’t find the valid pair
which would provide the target sum. Therefore, Go to next Iteration on Outer
Loop and start iterating the array from next index till end in inner loop. 2nd
Iteration on outer loop:
Again after all iterations of the inner loop, we couldn’t get the required pair so
iterated to the next element in the Outer Loop.
3rd Iteration on outer loop:
We will see that now in 4th Iteration of outer loop, we will get the required result:
4th Iteration on outer loop:
Now lets come back to our topic of discussion, as soon as we get the exact pair
whose sum equals the target value, we will return the indexes from outer and
inner loops and display the output. Please note that we don’t need the outer loop
till all elements. Since we always need to find 2 integers for output, It would be
enough to iterate the outer loop by N – 1.
Time complexity will be O(N ^ N) since there are 2 nested loops iterated till end.
Although we may not need to iterate through all the elements in the outer loop.
Now lets try to show ABAP code in OLD and NEW syntaxes separately so that
readers can easily observe the usage of new syntax.
OpCmized Approach:
This problem can be optimized using the famous two-pointer technique.
It’s the use of two different pointers (usually to keep track of array or string
indices) to solve a problem involving said indices with the benefit of saving time
and space. However, the technique basically uses the fact that the input array is
sorted.
Applying two-pointer technique :
1. Sort the input array( if it’s not sorted already in the problem statement )
2. Initialize start pointer with the first index and end pointer with the last index.
3. Move the left pointer ‘i’ towards right when the sum of Arr[i] and Arr[j] is less
than K.
4. Move the right pointer ‘j’ towards the left when the sum of Arr[i] and Arr[j] is
greater than K.
5. Return the indices when the sum is found.
Consider an array arr[] = { 5, 1, 2, 6, 4, 3 } and value of k = 10. We need to
store the indices of the input array since It will be changed after sorting.
Now, Initialize the start pointer with Arr[1] (highlighted in red) and end pointer
with Arr[6] (highlighted in green) as below:
Since the sum of these pointers are less than the target value(10), Move the left
pointer towards the right and keep the right pointer as it is.
Since the sum of these pointers are less than the target value(10), Move the left
pointer towards the right and keep the right pointer as it is.
Since the sum of these pointers are less than the target value(10), Move the left
pointer towards the right and keep the right pointer as it is.
Wonderful!! We have got the right pair whose sum equals the target.
So, we will prepare the output table and return the relevant indexes i.e. [5,4]
N : size of array
Time complexity for this algorithm will be linear since there is only one LOOP .
However, we have to sort the input array so time complexity will be : O(nlogn)
also known as loglinear complexity.
Note:- If the input array is sorted already in the problem statement, then time
complexity will be O(n) also known as linear time complexity. However, This
approach is still optimized as compared to brute force as we have successfully
avoided the nested loop.
Sample Source Code:
TYPES: tyt_input TYPE TABLE OF i WITH EMPTY KEY,
BEGIN OF tys_value, index TYPE i, value TYPE i, END OF
tys_value, tyt_index_input TYPE TABLE OF tys_value WITH EMPTY KEY. DATA:
lv_k TYPE i.
“ Input Array
DATA(lt_input) = VALUE tyt_input( ( 7 ) ( 10 ) ( 30 ) ( 9 ) ( 3 ) ).
"Input for target sum cl_demo_input=>add_field( CHANGING
field = lv_k ). cl_demo_input=>request( ).
“Prepare new table with indexes
DATA(lt_index) = VALUE tyt_index_input( FOR lv_value IN lt_input INDEX INTO lv_index
( index = lv_index value = lv_value ) ).
“Sort the new table with input values (Keep-in mind that indexes will also be changed “when
sorted that’s why we used another internal table to preserve the original indexes SORT lt_index BY
VALUE.
“Ini5alize start and end pointers DATA(lv_start)
= 1.
DATA(lv_end) = lines( lt_input ).
“Itera5on through the Input array LOOP AT lt_index
INTO DATA(lv_input).
“ Calculate the sum of the values at start and end pointers DATA(lv_sum) = lt_index[ lv_start ]value
+ lt_index[ lv_end ]-value.
“ When sum is more than the target value, move the end pointer to the len
IF lv_sum > lv_k. lv_end -= 1.
“ When sum is less than the target value, move the start pointer to the right
ELSEIF lv_sum < lv_k. lv_start +=
1.
ELSE.
“ Return the original indexes at start and end pointer when sum equals target
DATA(lt_output) = VALUE tyt_input( ( lt_index[ lv_start ]-index ) (
lt_index[ lv_end ]-index ) ). “ Exit from the loop EXIT.
ENDIF. ENDLOOP.
cl_demo_output=>display( lt_output ).
Alternate Approach:
There is another solution to use a temporary array(internal table) as a Hash Map
table. This
HashMap should store the complement of the previous iterated values. For every
new Iteration, we should first check if its complement already exists in the
HashMap. If found, we can collect the indices for the current iteration and get the
index of its complement from the input array to generate the final output and exit
from the loop.
Consider an array arr[] = { 5, 1, 2, 6, 4, 3 } and value of k = 10.
Complement of the array element against the target value would be : k –
arr[i] Initially, Input Array and HashMap will be shown as:
1st Iteration:
Arr[1] NOT IN HashMap[ ] so HashMap[1] = 10 – 5 = 5
2nd Iteration:
Arr[2] NOT IN HashMap[ ] so HashMap[2] = 10 – 1 = 9
3rd Iteration:
Arr[3] NOT IN HashMap[ ] so HashMap[3] = 10 – 2 = 8
4th Iteration:
Arr[4] NOT IN HashMap[ ] so HashMap[4] = 10 – 6 = 4
5th Iteration:
Arr[5] IN HashMap[ ] so we found the match.
Wonderful!! We have got the right pair whose sum equals the target. So we
will prepare the output table and return the relevant indexes. One would be
the current index and another would be the index of its
complement in the array.
N : size of array
Time complexity for this algorithm will be linear since there is only one LOOP and
unlike the previous method, we don’t need to sort the input array.
Time complexity would be : O(N)
Sample ABAP code can be found as follow:
Sample Source Code:
TYPES: tyt_input TYPE TABLE OF i WITH EMPTY KEY, DATA:
lv_k TYPE i.
" Input Array
DATA(lt_input) = VALUE tyt_input( ( 7 ) ( 10 ) ( 30 ) ( 9 ) ( 3 ) ).
" Reading hash table with index DATA(lt_hash) = VALUE
tyt_input( ).
“Itera5on through the Input array LOOP AT lt_input
INTO DATA(lv_input).
DATA(lv_tabix) = sy-tabix.
“ When current element is not found in hashmap, add it’s complement into hashmap
IF ( line_index( lt_hash[ table_line = lv_input ] ) = 0 ). APPEND ( lv_k - lv_input ) TO
lt_hash.
ELSE.
“ When current element is found in hashmap, append the current index and the
index of its complement into result table DATA(lt_output) = VALUE
tyt_input( ( lv_tabix )
( line_index( lt_input[ table_line =
lv_k - lv_input ] ) ) ).
EXIT.
ENDIF.
ENDLOOP.
Eight different sort algorithms implemented in ABAP
33 15 21,420
Bucket Sort
Bubble Sort
Merge Sort
Quick Sort
Selec8on Sort
Inser8on Sort
Heap Sort
Shell Sort
A very draD performance comparison
Sleep Sort in JavaScript
Some applica8on developers think that it is enough to know SORT keyword and how to use sorted table in ABAP for their
daily work without knowing how SORT is done internally. For me I can not say this assump8on is wrong. I personal
preference is to know something more thoroughly. We have learned various sort algorithms in the university, here I just list
my implementa8on on some of them using ABAP for my personal study purpose.
For each sort algorithm I will create a sta8c public class with a sort method which accepts an internal table with unsorted
Integer and an output table which are sorted. For simplifica8on reason the element in the internal table only consists of
unsigned integers ( >= 0 )
In ABAP the internal table is a perfect choice for bucket collec8on A small trap here is, array in most program language has
start index as 0, however in ABAP for internal table it is 1. So be careful about the possibility that 0 appears in the input
internal table.
Jerry’s ABAP implementa8on
And I also implement a version using JavaScript which can support nega8ve integer in Bucket Sort as well. See source code
here.
Bubble Sort
Algorithm introduc8on
I have implemented two variants, the only difference between them:
Variant 1 uses two nested DO LOOP, while variant 2 uses WHILE as inner LOOP.
Variant 1 uses tradi8onal keyword MODIFY itab FROM workarea INDEX index to swap the two adjacent element, while
variant 2 uses new grammar itab[ index ].
Merge Sort
Algorithm introduc8on
Again I have implemented two variants.
Variant1 – use Recursive
Callstack could be found below:
Quick Sort
Algorithm introduc8on
My implementa8on
SelecCon Sort
Algorithm introduc8on
My implementa8on
InserCon Sort
Algorithm introduc8on
My implementa8on
Heap Sort
Algorithm Introduc8on
My implementa8on
Shell Sort
Algorithm Introduc8on
My implementa8on
Meanwhile I am especially curious about how ABAP keyword SORT will behave against these eight sort algorithms, so I
create another two sort approaches.
The table type ZTSORTED_INT4 has line type INT4 with sorted table type.
Test code:
zcl_sort_helper=>start_measure( ).
DATA(lt_bubble) = zcl_bubblesort=>sort( lt_test_data ). WRITE: / 'Bubble Sort dura8on:' ,
zcl_sort_helper=>stop( ).
zcl_sort_helper=>start_measure( ).
DATA(lt_hashsort) = zcl_hashsort=>sort( lt_test_data ). WRITE: / 'Hash Sort dura8on:' ,
zcl_sort_helper=>stop( ).
zcl_sort_helper=>start_measure( ).
DATA(lt_heapsort) = zcl_hashsort=>sort( lt_test_data ). WRITE: / 'Heap Sort dura8on:' ,
zcl_sort_helper=>stop( ).
zcl_sort_helper=>start_measure( ).
DATA(lt_insertsort) = zcl_insertsort=>sort( lt_test_data ). WRITE: / 'Insert Sort dura8on:' ,
zcl_sort_helper=>stop( ).
zcl_sort_helper=>start_measure( ).
DATA(lt_mergesort) = zcl_mergesort=>sort( lt_test_data ). WRITE: / 'Merge Sort dura8on:'
, zcl_sort_helper=>stop( ).
zcl_sort_helper=>start_measure( ).
DATA(lt_quicksort) = zcl_quicksort=>sort( lt_test_data ). WRITE: / 'Quick Sort dura8on:' ,
zcl_sort_helper=>stop( ).
zcl_sort_helper=>start_measure( ).
DATA(lt_selectsort) = zcl_selectsort=>sort( lt_test_data ). WRITE: / 'Select Sort dura8on:' ,
zcl_sort_helper=>stop( ). zcl_sort_helper=>start_measure( ).
DATA(lt_shellsort) = zcl_shellsort=>sort( lt_test_data ). WRITE: / 'Shell Sort dura8on:' ,
zcl_sort_helper=>stop( ).
zcl_sort_helper=>start_measure( ).
DATA(lt_sort_keyword) = zcl_sort_via_keyword=>sort( lt_test_data ). WRITE: / 'ABAP Sort keyword
dura8on:' , zcl_sort_helper=>stop( ).
zcl_sort_helper=>start_measure( ).
DATA(lt_sort_table) = zcl_abap_sorgable=>sort( lt_test_data ).
WRITE: / 'ABAP Sorted table dura8on:' , zcl_sort_helper=>stop( ).
ASSERT lt_bubble = lt_hashsort.
ASSERT lt_hashsort = lt_heapsort.
ASSERT lt_heapsort = lt_insertsort.
ASSERT lt_insertsort = lt_mergesort. ASSERT lt_mergesort =
lt_quicksort.
ASSERT lt_quicksort = lt_selectsort.
ASSERT lt_shellsort = lt_selectsort.
ASSERT lt_sort_keyword = lt_shellsort.
ASSERT lt_sort_table = lt_sort_keyword.
The ABAP SORT keyword and SORTED TABLE did a really good job here The
complete source code for this blog could be found from my github.
Test output:
WriCng algorithms in ABAP (SAP BTP ABAP Environment 2211 Release)
Example 1:
Output: 6
Example 2:
Example 3:
Constraints:
5
1 <= nums.length <= 10
4 4
-10 <= nums[i] <= 10
Solu:on
Time Complexity: O(n)
ABAP
PUBLIC SECTION.
* Mandatory declara8on
INTERFACES if_oo_adt_classrun.
PROTECTED SECTION.
PRIVATE SECTION.
TYPES ty_nums TYPE STANDARD TABLE OF i WITH EMPTY KEY.
METHODS kadaneAlgorithm
IMPORTING lt_nums TYPE STANDARD TABLE RETURNING
VALUE(rv_msf) TYPE i.
ENDCLASS.
CLASS zcl_algo_kadane IMPLEMENTATION.
local variables
DATA : lv_meh TYPE i VALUE 0, "max ending here
lv_temp TYPE i VALUE 0, "sum lv_start TYPE i
IF ( lv_meh < 0 ).
lv_meh = 0. lv_temp
= sy-tabix.
ENDIF. ENDLOOP.
UNASSIGN <lf_wa>.
FREE : lv_meh, lv_temp, lv_start, lv_end.
ENDMETHOD.
ENDCLASS.
JavaScript
Python
class Solu8on: def maxSubArray(self, nums: List[int]) -> int:
You want to maximize your profit by choosing a single day to buy one stock and choosing a different day in
the future to sell that stock.
Return the maximum profit you can achieve from this transac8on. If you cannot achieve any profit, return
0.
Example 1:
Example 2:
Constraints:
5
1 <= prices.length <= 10
4
0 <= prices[i] <= 10
Solu:on
Time Complexity: O(n)
ABAP
CLASS zcl_stock DEFINITION
PUBLIC
FINAL
CREATE PUBLIC .
PUBLIC SECTION.
* Mandatory declara8on
INTERFACES if_oo_adt_classrun.
METHODS StockBuySell
IMPORTING lt_prices TYPE ty_prices RETURNING VALUE(rv_max_profit)
TYPE i.
ENDCLASS.
METHOD StockBuySell.
DATA(lv_min_price) = lt_prices[ 1 ].
ENDMETHOD.
ENDCLASS.
JavaScript
return lv_max_profit;
};
Python
We will use the integers 0, 1, and 2 to represent the color red, white, and blue, respec8vely.
You must solve this problem without using the library’s sort func8on.
Example 1:
Input: nums =
[2,0,2,1,1,0] Output:
[0,0,1,1,2,2]
Example 2:
Constraints:
n ==
nums.len
gth 1 <=
n <= 300
nums[i] is either 0, 1, or 2.
Follow up: Could you come up with a one-pass algorithm using only constant extra space?
Solu:on
Time Complexity: O(n)
ABAP
CLASS zcl_algo_dnf DEFINITION
PUBLIC
FINAL
CREATE PUBLIC .
PUBLIC SECTION.
* Mandatory declara8on
INTERFACES if_oo_adt_classrun.
PROTECTED SECTION.
PRIVATE SECTION.
TYPES ty_nums TYPE STANDARD TABLE OF i WITH EMPTY KEY. DATA lt_nums TYPE
STANDARD TABLE OF i WITH EMPTY KEY.
METHODS sortNumbers
CHANGING lt_nums TYPE STANDARD TABLE.
METHODS swapNumbers
CHANGING lt_nums TYPE STANDARD TABLE lv_i
TYPE i lv_j TYPE i.
ENDCLASS.
METHOD if_oo_adt_classrun~main.
FREE lt_nums.
ENDMETHOD.
METHOD sortNumbers.
* indexes
DATA(lv_low) = 1.
DATA(lv_mid) = 1.
DATA(lv_high) = lines( lt_nums ).
WHILE lv_mid <= lv_high.
CASE lt_nums[ lv_mid ].
WHEN 0. swapNumbers( CHANGING lt_nums = lt_nums
lv_i = lv_low lv_j = lv_mid ). lv_low += 1. lv_mid
+= 1. WHEN 1.
lv_mid += 1.
WHEN 2. swapNumbers( CHANGING lt_nums = lt_nums
lv_i = lv_mid lv_j = lv_high ). lv_high -= 1.
ENDCASE. ENDWHILE.
ENDMETHOD.
METHOD swapNumbers.
FREE lv_temp.
ENDMETHOD.
ENDCLASS.
JavaScript
/**
* @param {number[]} nums
* @return {void} Do not return anything, modify nums in-place instead.
*/
var sortColors = func8on (nums) {
var lv_low = 0, lv_mid = 0,
lv_high = nums.length - 1;
while (lv_mid <= lv_high) { switch (nums[lv_mid]) { case 0:
swapNumbers(nums, lv_low, lv_mid);
lv_low += 1; lv_mid += 1; break; case 1:
lv_mid += 1; break; case 2: swapNumbers(nums,
lv_mid, lv_high);
lv_high -= 1; break;
}
} };
Python
For example, for arr = [1,2,3], the following are all the permuta8ons of arr: [1,2,3], [1,3,2], [2, 1, 3], [2,
3, 1], [3,1,2], [3,2,1].
The next permuta8on of an array of integers is the next lexicographically greater permuta8on of its
integer. More formally, if all the permuta8ons of the array are sorted in one container according to their
lexicographical order, then the next permuta8on of that array is the permuta8on that follows it in the
sorted container. If such arrangement is not possible, the array must be rearranged as the lowest possible
order (i.e., sorted in ascending order).
The replacement must be in place and use only constant extra memory.
Example 1:
Example 2:
Example 3:
Constraints:
1 <= nums.length
<= 100
0 <= nums[i] <= 100
Solu:on
Time Complexity: O(n)
PUBLIC SECTION.
* Mandatory declara8on
INTERFACES if_oo_adt_classrun.
PROTECTED SECTION.
PRIVATE SECTION.
TYPES ty_nums TYPE STANDARD TABLE OF i WITH EMPTY KEY.
METHODS getNextPermuta8on
CHANGING lt_nums TYPE STANDARD TABLE.
METHODS reverseNumbers
CHANGING lt_nums TYPE ty_nums lv_i
TYPE i lv_j TYPE i.
METHODS swapNumbers
CHANGING lt_nums TYPE ty_nums lv_i
TYPE i lv_j TYPE i.
ENDCLASS.
METHOD if_oo_adt_classrun~main.
* step: 4: manipula8ons lv_j += 1. lv_i = lines( lt_nums ).
* step: 5
reverseNumbers( CHANGING lt_nums = lt_nums lv_i =
lv_j lv_j = lv_i ). ENDIF.
ENDMETHOD.
METHOD reverseNumbers.
WHILE lv_i < lv_j. swapNumbers( CHANGING lt_nums =
lt_nums lv_i = lv_i lv_j = lv_j ).
lv_i += 1. lv_j -= 1.
ENDWHILE.
ENDMETHOD.
METHOD swapNumbers.
DATA(lv_temp) = 0.
ENDCLASS.
Python
# index of the first element that is smaller than the element to its right
lv_index = -1
/**
* @param {number[]} nums
* @return {void} Do not return anything, modify nums in-place instead.
*/ var nextPermuta8on = func8on (nums) {
};
func8on reverse_numbers(array, i, j) {
while (i < j) swap_numbers(array, i++, j--); }