Python Interview Questions on Searching and Sorting

We have compiled most frequently asked Python Interview Questions which will help you with different expertise levels.

Python Interview Questions on Searching and Sorting

Sequential Search

In the chapter based on Python operators, we have seen that we can make use of the membership operator ‘in’ to check if a value exists in a list or not.

    >>> list.1 = [1,2,3,4,5,6,71
    >>> 3 in list1
   True
    >>> 8 in list1
    False
    >>>

This is nothing but searching for an element in a list. We are going to look at how elements can be searched and how process efficiency can be improved. We start by learning about sequential search.

The simplest way of searching for an element in a sequence is to check every element one by one. If the element is found then the search ends and the element is returned or else the search continues till the end of the sequence. This method of searching is known as linear search or sequential search. It follows a simple approach but it is quite an inefficient way of searching for an element because we move from one element to the other right from the beginning to end and if the element is not present in the sequence we would not know about it till we reach the last element.

Time analysis for sequential search:

  • Best scenario is that the element that we are looking for is the very first element in the list. In this case, the time complexity will be 0(1).
  • The worst scenario would be if we traverse throughout the entire sequence and realize that the element that we are looking for, does not exist. In this case, the time complexity will be O(n).

Python Interview Questions on Searching and Sorting chapter 14 img 1

Question 1.
Sequential search is also known as _______
Answer:
Linear Search

Question 2.
How are the elements reviewed in sequential search?
Answer:
The elements are reviewed one at a time in sequential terms.

Question 3.
When does the sequential search end?
Answer:
The sequential search ends when an element is found or when the end of the sequence is reached.

Question 4.
Write code to implement sequential search.
Answer:
The sequential search can be implemented as follows:

  • The function takes two values: seq list which is the list and target_ num which is the number to search in the list.
  • We set search_flag = 0 if the target number is found in the list we will set the search_flag to 1 else we let it be 0.
  • We iterate through the list comparing each element in the list with the target_num.
  • If a match is found we print a message and update the search_flag to 1.
  • After the “for” loop if the search_flag is still 0 then it means that the number was not found.

Code

def sequential__search (seq_list, target_num) :
    search_flag = 0
    for i in range(len(seq_list)):
        if seq_list[i] == target_num:
           print("Found the target number ", target_num, " at index", i,".")
            search_flag = 1;
    if search_flag == 0:
       print("Target Number Does Not Exist.Search Unsuccessful.")

Execution

seq_list = [1,2,3,4,5,6,7,8,2,9,10,11,12,13,14,15, 16]
target__num = input ("Please enter the target number : ")
sequential_search(seq_list, int(target_num))

Output 1

Please enter the target number: 5
Found the target number 5 at index 4.

Output 2

Please enter the target number: 2
Found the target number 2 at index 1.
Found the target number 2 at index 8.

Output 3

Please enter the target number: 87
Target Number Does Not Exist. Search Unsuccessful.

Question 5.
How would you implement a sequential search for an ordered list?
Answer:
When elements in a list are sorted, then many times there may not be the need to scan the entire list. The moment we reach an element that has a value greater than the target number, we know that we need not go any further.

Step 1: We define a function sequential_search() that takes two arguments – a list (seq_list) and the number that we are looking for (target num).

def sequential_search(seq_list, target_num):

Step 2: The first thing we do is set define a flag (search_flag) and set it to “False’’ or “0” value. The flag is set to “True” or “1” if the element is found. So, after traversing through the list if the search_flag value is still “False” or “0”, we would know that the number that we are looking for does not exist in the list.

def sequential__search (seq_list, target_num) :
    search_flag = 0

Step 3: Now, it’s time to check the elements one by one so, we define the for loop:

def sequential_search(seq_list, target_num):
    search_flag = 0
    for i in range(len(seq_list)):

Step 4: We now define how the elements are compared. Since it is an ordered list for every “i” in seq_list we have to check if i > target_num. If yes, then it means that there is no point moving further as it is an ordered list and we have reached an element that is greater than the number that we are looking for. However, if seq_list[i] == target_num then, the search is successful and we can set the search_flag to 1.

def sequential_search(seq_list, target^num):
    search_flag = 0
    for i in range(len(seq_list)):
        if seq_list[i] > target_num:
           print("search no further.")
           break;
       elif seq_list[i] == target_num:
            print("Found the target number ", target_num, " at index", i,".")
            search_flag = 1;

Step 5: After the for loop has been executed if the value of search_flag is still 0 then a message stating that the target number was not found must be displayed.

Code

def sequential_search(seq_list, target_num):
      search_flag = 0
      for i in range(len(seq_list)):
          if seq_list[i] > target_num:
             print("search no further.")
             break;
         elif seq_list[i] == target_num:
              print("Found the target number ", target_num, " at index", i,".")
              search_flag = 1 ;

      if search_flag == 0 ;
      print ("Target Number Does Not Exist. search Unsuccessful.")

Execution

seq_list = [1,2,3,4,5,6,7,8,2,9,10,11,12,13,14,15, 16]
target_num = input ("Please enter the target number : ")
sequential_search(seq_list, int(target_num))

Output 1

Please enter the target number: 2
Found the target number 2 at index 1.
Found the target number 2 at index 2.
search no further.
>>>

Output 2

Please enter the target number: 8
Found the target number 8 at index 8.
Search no further.
>>>

Output 3

Please enter the target number: 89
Target Number Does Not Exist. Search Unsuccessful.
>>>

Binary Search

A binary search is used to locate a target value from a sorted list. The search begins from the center of the sequence. The element present at the center is not equal to the target number it is compared with the target number. If the target number is greater than the element at the center then it means that we need to search for the number in the right half of the list and the left half need not be touched. Similarly, if the target number is less than the element present in the center then we will have to direct our search efforts towards the left. This process is repeated till the search is completed. The beauty of binary search is that in every search operation the sequence is cut into half and focus is shifted to only that half that has chances of having the value.

Python Interview Questions on Searching and Sorting chapter 14 img 2

Question 6.
Write a code to implement the binary search function.
Answer:
The binary search can be implemented in the following manner:
Step 1: Define the binary_search function. It takes 4 parameters:

  • sorted list: the input list that is in sorted form
  • target_num: the number that we are looking for
  • starting_point: the place from where we want to start searching, default value = 0
  • end_point: The endpoint for search, default value = None

Note that the list will be split in half in every step so the starting and ending point may change in every search operation.

def binary_search(sorted_list, target_num, start_ point=0, end_point=None):

Step 2: Do the following:

  • Set the search_flag to “False”
  • If the end_point is not provided, it would have the default value of “None”, set it to the length of the input list.
def binary_search(sorted_list, target_num, 
start_point=0, end_point=None):
     search_flag = False
     if end_point == None:
        end_point = len(sorted_list)-1

Step 3: Check, the start_point should be less than the endpoint. If that is true, do the following:

  • Get midpoint index value: mid_point = (end_point+start_point)//2
  • Check the value of the element at mid_point. Is it equal to the target_ num?
  • If sorted_lLst[midjioint] == target num1
  • Set search flag to True
  • If not check if the value at mid_point is greater than target_num :
  • sorted_list[mid_point] > target num
  • If yes, then we can discard the right side of the list now we can repeat the search from beginning to mid_point-1 value. Set
    endpoint to mid_point – 1. The starting point can remain the same(0).
  • The function should now call itself with:
  • sorted_list: same as before
  • target_num: same as before
  • starting point: same as before
  • endpoint: mid_point – 1
  • If not check if the value at mid_point is lesser than target num :
  • sorted_list[mid_point] < target_num
  • If yes, then the left side of the list is not required. We can repeat the search from mid_point+1 to the end of the list. Set starting point to mid_point+1. The ending_point can remain the same.
  • The function should now call itself with:
  • sorted_list: same as before
  • target_num: same as before
  • starting point: mid_point+l
  • end_point: same as before
  • If at the end of this procedure the search_flag is still set to “False”, then it means that the value does not exist in the list.

Code

def binary_search(sorted_list, target_num, start_ point=0, end_point=None):
       search_flag = False
       if end_point == None:
          end_point = len(sorted_list)-1
       if start_point < end_point:
          mid_point = (end_point+start_point)//2
          if sorted_list[mid_point] == target_num:
             search_flag = True
             print(target_num," Exists in the list at ",sorted_list.index(target_num))
             elif sorted_list[mid_point] > target_num:
                  end_point = mid_point-l 
                  binary_search(sorted_list, target_ num,start_point, end_point)
            elif sorted_list[mid_point] < target_num:
            start_point = mid_point+l 
            binary_search(sorted_list, target_num, start_point, end_point)
       elif not search_flag:
             print(target_num," Value does not exist")

Execution

sorted_list=[ 1,2,3,4,5,6,7,8,9,10,11,12,13]
binary_search(sorted_list, 14)
binary_search(sorted_list,0)
binary_search(sorted_list,5)

Output

14 Value does not exist 
0 Value does not exist 
5 Exists in the list at 4

Hash Tables

Hash Tables are data structures where a hash function is used to generate the index or address value for a data element. It is used to implement an associative array that can map keys to values. The benefit of this is that it allows us to access data faster as the index value behaves as a key for data value. Hash tables store data in key-value pairs but the data is generated using the hash function. In Python, the Hash Tables are nothing but Dictionary data type. Keys in the dictionary are generated using a hash function and the order of data elements in Dictionary is not fixed. We have already learned about various functions that can be used to access a dictionary object but what we actually aim at learning here is how hash tables are actually implemented.

We know that by binary search trees we can achieve the time complexity of O(logn) for various operations. The question that arises here is that can search operations be made faster? Is it possible to reach a time complexity of 0(1)11 This is precisely why hash tables came into existence? Like in a list or an array if the index is known, the time complexity for search operation can become 0(1). Similarly, if data is stored in key-value pairs, the result can be retrieved faster. So, we have keys and we have slots available where the values can be placed. If we are able to establish a relationship between the slots and the key it would be easier to retrieve the value at a fast rate. Look at the following figure:

Python Interview Questions on Searching and Sorting chapter 14 img 3

The key value is not always a nonnegative integer, it can be a string also, whereas the array has an index starting from 0 to length_of_array -1. So there is a need to do prewashing in order to match the string keys to indexes. So, for every key, there is a need to find an index in an array where the corresponding value can be placed. In order to do this, we will have to create a hash( ) function that can map a key of any type to a random array index.

During this process, there are chances of collision. Collision is when we map two keys to the same index as shown in the following figure:

Python Interview Questions on Searching and Sorting chapter 14 img 4

To resolve collision we can use chaining. Chaining is when values are stored -in the same slot with the help of a linked list as shown in the following figure:

Python Interview Questions on Searching and Sorting chapter 14 img 5

However, there can be cases of more than one collision for the same spot, and considering the worst-case scenario where there is a need to insert all values as elements of a linked list, it can be a tough situation that will have a severe impact on the time complexity. Worst case scenario will be if we land up placing all values as linked list elements at the same index.

To avoid this scenario we can consider the process of open addressing. Open addressing is the process of creating a new address. Consider a case where if there is a collision we increment the index by 1 and place the value there as shown below, there is collision while placing val3, as val2 already exists at index 1. So, the index value is incremented by 1 (1+1 =2) and val3 is placed at the index

Python Interview Questions on Searching and Sorting chapter 14 img 6

Had there been any other value at index 2 then the index would have incremented again and val3 could be placed at index 3. This means that this process of incrementing the index is continued till an empty slot is spotted. This is called Linear probing. Quadratic probing on the other hand increments by two times the index value. So, the search for the empty slots is done at a distance of 1,2,4,8, and so on. Rehashing is the process of hashing the result obtained again to find an empty slot.

The purpose of the hash function is to calculate an index from which the right value can be found therefore its job would be:

  1. To distribute the keys uniformly in the array.
  2. If n is the number of keys and m is the size of an array, the hash( ) = n%m(modulo operator) in case we use integers as keys.
  3. Prefer to use prime numbers both for array and the hash function for uniform distribution
  4. For string keys, you can calculate the ASCII value of each character and add them up and make a modulo operator on them

In many scenarios, hash tables prove to be more efficient than the search trees and are often used in caches, databases, and sets.
Important points:

  1. You can avoid clustering by using prime numbers.
  2. The number of entries divided by the size of the array is called the load factor.
  3. If the load factor increases the number of collisions will increase. This will reduce the performance of the hash table.
  4. Resize the table when the load factor exceeds the given threshold. However, this would be an expensive option as the hashes of the values entered will change whenever resizing is done and this can take O(n) to complete. Hence dynamic size array may be inappropriate for real-time scenarios.

Question 7.
What does the hash function do?
Answer:
The purpose of a hash function is to map the values or entries into the slots that are available in a hash table. So, for every entry, the hash function will compute an integer value that would be in the range of 0 to m-1 where m is the length of the array.

Question 8.
What is a remainder hash function? What are the drawbacks? Write the code to implement the remainder hash function.
Answer:
The remainder hash function calculates the index value by taking one item at a time from the collection. It is then divided by the size of the array and the remainder is returned.
h(item) = item% m, where m = size of the array Let’s consider the following array:
[18, 12,45,34, 89, 4]
The above array is of size 8.

Python Interview Questions on Searching and Sorting chapter 14 img 7

Drawback: You can see here that 18 and 34 have the same hash value of 2 and 12 and 4 have the same hash value of 4. This is a case of collision as a result when you execute the program, values 18 and 12 are replaced by 34 and 4 and you will not find these values in the hash table.

Let’s have a look at the implementation:

Step1: Define the hash function that takes a list and size of the array as input.
def hash(list_items, size):

def hash(list items, size) :

Step2: Do the following:

  • Create an empty list.
  • Now populate this key ‘from the numbers 0 to size mention. This
    example takes a list of 8 elements so we are creating a list [0, 1, 2, 3, 4, 5,6, 7].
  • Convert this list to diet using from keys( ). We should get a dictionary object of form {0: None, 1: None, 2: None, 3: None, 4: None, 5: None, 6: None, 7: None}. This value is assigned to hash_table.
def hash(list_items, size):
temp_list =[ ]
for i in range(size):
      temp_list.append(i)
'hash_table = diet.fromkeys(temp_list)

Step3:

  • Now iterate through the list.
  • Calculate the index for every item by calculating item%size.
  • For the key value in the hash_table = index, insert the item.

Code

def hash(list_items, size):
     temp_list =[ ]
     for i in range(size):
          temp_list.append(i)
     hash_table = diet.fromkeys(temp_list)
     for item in list_items:
         i = item%size
         hash_table[i] = item
    print("value of hash table is : ",hash_table)

Execution

list_items = [18,12,45,34,89,4]
hash(list_items, 8)

Output

value of hash table is : {0: None, 1: 89, 2: 34,
3: None, 4: 4, 5: 45, 6: None, 7: None}
>>>

Question 9.
What is a folding hash function?
Answer:
The folding hash function is a technique used to avoid collisions while hashing. The items are divided into equal-size pieces, they are added together and then the slot value is calculated using the same hash function (item%size).

Suppose, we have a phone list as shown below:

phone_list= [4567774321, 4567775514, 9851742433, 4368884732]

We convert every number to a string, then each string is converted to a list, and then each list is appended to another list and we get the following result:
[[‘4’, ‘5’, ‘6’, ‘7’, ‘7’, ‘7\ ‘4’, ‘3’, ‘2’, ‘1’], [‘4’, ‘5’, ‘6’, ‘7’, ‘7’, ‘7’, ‘5’, ‘5’’, ‘1’, ‘4’], [‘9’, ‘8’, ‘5’, ‘1’, ‘7’, ‘4’, ‘2’, ‘4’, ‘3’, ‘3’], [‘4’, ‘3’, ‘6’, ‘8’, ‘8’, ‘8’, ‘4’, ‘7’, ‘3’, ‘2’]]

Now from this new list, we take one list item one by one, for every item we concatenate two characters convert them to integer, and then concatenate next to characters convert them to integer, and add the two values and continue this till we have added all elements. The calculation will be something like this:
[‘4’, ‘5’, ‘6’, ‘7’, ‘7’, ‘7’, ‘4’, ‘3’, ‘2’, ‘1’]

1. items =45
string val = 45
integer value = 45
hash value= 45

2. items =67
string val = 67
integer value = 67
hash value= 45+67 =112

3. items =77
string val = 77
integer value = 77
hash value= 112+77 =189

4. items =43
string val = 43
integer value = 43
hash value= 189+43 = 232

5. items =21
string val = 21 ,
integer value = 21
hash value= 232+21 = 253 Similarly,
[‘4’, ‘5’, ‘6’, ‘7’, ‘7’, ‘7’, ‘5’, ‘5’, ‘1’, ‘4’] will have a hash value of 511.
[‘9’, ‘8’, ‘5’, ‘1’, ‘7’, ‘4’, ‘2’, ‘4’, ‘3’, ‘3’] will have a hash value of 791.
[‘4’, ‘3’, ‘6\ ‘8’, ‘8’, ‘8’, ‘4’, ‘7’, ‘3’, ‘2’] will have a hash value of 1069.
We now call the hash function for [253, 531, 791, 1069] for size 11.
Python Interview Questions on Searching and Sorting chapter 14 img 8

So, the result we get is:
{0: 253, 1: None, 2: 1069, 3: None, 4: None, 5: 511, 6: None, 7: None, 8: None, 9: None, 10: 791}

Question 10.
Write the code to implement the coding hash function.
Answer:
Let’s look at the execution statements for this program:

phone_list = [4567774321, 4567775514, 9851742433, 4368884732]
str_phone_values = convert_to_string(phone_list)
folded_value = foldingjiash(str_phone_values)
folding_hash_table = hash(folded_value,11)
print(folding_hash_table)

1. A list of phone numbers is defined: phonejist = [4567774321, 4567775514, 9851742433, 4368884732]
2. The next statement “str_phonepy allies = convert_to_string(phone_ list)” calls a function convert to_string( ) and passes the phone_list as argument. The function in turn returns a list of lists. The function takes one phone number at a time converts it to a list and adds to new list. So, we get the output as: [[‘4’, ‘5’, ‘6’, ‘7’, ‘7’, ‘7’, ‘4’, ‘3’, ‘2’, M’], [‘4’, ‘5’, ‘6’, ‘7’, ‘7’, ‘7’, ‘5’, ‘5’, ‘1’, ‘4’], [‘9’, ‘8’, ‘5’, ‘1’, ‘7’, ‘4’, ‘2’, ‘4’, ‘3’, ‘3’], [‘4’, ‘3’, ‘6’, ‘8’, ‘8’, ‘8’, ‘4’, ‘7’, ‘3’, ‘2’]]. The following steps are involved in this function:

a. Define two lists a phone_list[ ]
b. For elements in phone_list, take every element i.e. the phone number one by one and:
i. convert the phone number to string: temp_string = str(i)
ii. Convert each string to list: tempjist = list (temp_string)
iii. Append the list obtained to the phone_list defined in previous step.
iv. Return the phone_list and assign values to str_phone_ values

def convert_to_string(input_list):
phone_list=[ ]
for i in input_list:
temp_string = str(i)
temp_list = list(temp_string)
phone_list.append(temp_list)
return phone_list

3. The list str_phone_values is passed on to folding_hash( ). This method takes a list as input.
a. It will take each phone list element which is also a list.
b. Take one list item one by one.
c. For every item concatenate first two characters convert them to integer and then concatenate next to characters convert them to integer and add the two values.
d. Pop the first two elements from thr list.
e. Repeat c and d till we have added all elements.
f. The function returns a list of hash values.

def folding_hash(input_list):
    hash_final = [ ]
    while len(input_list) > 0:
         hash_val = 0
         for element in input_list:
             while len(element) > 1:
                 stringl = element[0]
                 string2 = element[1]
                 str_contbine = string1 + string2
                 int_combine = int(str_combine)
                 hash_val += int_combine
                 element.pop(0)
                 element.pop(0)
             if len(element) > 0:
                hash_val += element[0]
             else:
                pass
             hash_final. append (hash_val)
        return hash final

4. Call hash function for size 11. The code for the hash function is same.

def hash(list_items, size):
    temp_list =[ ]
    for i in range (size) :
        temp_list.append(i)
    hash_table = diet.fromkeys(temp_list)
    for item in list_items:
        i = item%size
        hash_table[i] = item
    return hash_table

Code

def hash(list_items, size):
    temp_list =[ ]
    for i in range(size):
        temp_list.append(i)
    hash_table = diet.fromkeys(temp_list)
    for item in list_items:
        i = item%size
        hash_table[i] = item
   return hash_table
def convert_to_string(input_list):
    phone_list=[ ]
    for i in input_list:
        temp_string = str(i)
        temp_list = list(temp_string)
        phone_list.append(temp_list)
   return phone_list
def folding_hash(input_list):
    hash_final = [ ]
    while len(input_list) > 0:
         hash_val = 0
         for element in input_list:
             while len(element) > 1:
                 string1 = element[0]
                 string2 = element[1]
                 str_combine = string1 + string2
                 int_combine = int(str_combine)
                 hash_val += int_combine
                 element.pop(0)
                 element.pop(0)
            if len(element) > 0:
                hash_val += element[0]
           else:
              pass
           hash_final. append (hash_val)
    return hash_final

Execution

phone_list = [4567774321, 4567775514, 9851742433, 4368884732]
str_phone_values = convert_to_string(phone_list)
folded_value = folding_hash (str_phone_valu.es)
folding_hash_table = hash(folded_value,11)
print(folding_hash_table)

Output

{0: 253, 1: None, 2: 1069, 3: None, 4: None, 5:
511, 6: None, 7: None, 8: None, 9: None, 10: 791}

In order to store phone numbers at the index, we slightly change the hash() function;

  1. The hash( ) function will take one more parameter : phone_list
  2. After calculating the index the corresponding element from the phone_list is saved instead of the folded_value.
def hash(list_items,phone_list, size):
    temp_list =[ ]
    for i in range(size):
        temp_list.append(i)
   hash_table = diet.fromkeys(temp_list)
   for i in range(len(list_items)):
       hash_index = list_items[i]%size
       hash_table[hash_index] = phone_list[i]
   return hash_table

Execution

phone_list = [4567774321, 4567775514, 9851742433, 4368884732]
str_phone_values = ‘convert_to_string(phone_list)
folded_value = folding_hash(str_phone_values)
folding_hash_table = hash (folded_value,phone_ list,11)
print(folding_hash_table)

Output

{0: 4567774321, 1: None, 2: 4368884732, 3: None,
4: None, 5: 4567775514, 6: None, 7: None, 8: None,
9: None, 10: 9851742433}

Bubble sort

Bubble sort is also known as sinking sort or comparison sort. In bubble sort, each element is compared with the adjacent element, and the elements are swapped if they are found in the wrong order. However, this is a time-consuming algorithm. It is simple but quite inefficient.

Python Interview Questions on Searching and Sorting chapter 14 img 9

Question 10.
How will you implement bubble sort in Python?
Answer:
The code for a bubble sort algorithm is very simple.
Step 1: Define the function for bubble sort. It would take the list that needs
to be sorted as input.

def bubble_sort(input_list):

Step 2:
1. Set a loop for i in range len(input_list)
a. Inside this for loop set another loop for j in range len(input_ list)-i-1).
b. For every i, in the nested loop value at index j, is compared with the value at index j+1. If the value at index j+1 is smaller than the value at index j then the values are swapped.
c. After the for loop is overprint the sorted list.

Code

def bubble_sort(input_list):
    for i in range(len(input_list)):
        for j in range(len(input_list)-i-1):
            if input_list[j]>input_list[j+1]:
               temp = input_list[j]
               input_list[j]=input_list[j+1]
               input_list[j+1]= temp
    print(input_list)

Execution

x = [7,1,3,6,2,4]
print("Executing Bubble sort for ",x)
bubble_sort(x)

y = [23,67,12,3,45,87,98,34]
print("Executing Bubble sort for ",y)
bubble_sort(y)

Output

Executing Bubble sort for [7, 1, 3, 6, 2, 4]
[1, 2, 3, 4, 6, 7] 
Executing 98, 34] Bubble sort for [23, 67, 12, 3, 45, 87,
[3, 12, 23 , 34, 45, 67, 87, 98]

Question 11.
Write code to implement selection sort.
Answer:
Step 1: Define the function for selection_sort. It would take the list that
needs to be sorted as input.

def selection_sort(input_list):

Step 2:
1. Set a loop for i in range len(input_list)
a. Inside this for loop set another loop for j in range (i+1, len(input_ list)-i-l))
b. For every i, in the nested loop value at index j is compared with the value at index i. If the value at index j is smaller than the value at index i then the values are swapped.
c. After the for loop is overprint the sorted list.

Code

def selection_sort(input_list):
    for i in range(len(input list)-1) :
        for j in range(i+1,len(input list)):
            if input_list[j] < input_list[i]:
               temp = input_list[j]
               input_list[j] = input_list[i]
               input list[i] = temp
  print(input list)

Execution

selection_sort([15,10,3,19,80,85])

Output

[3, 10, 15, 19, 80, 85]

Insertion Sort

In insertion sort, each element at position x is compared with elements located at position x-1 to position 0. If the element is found to be less than any of the values that it is compared to then the values are swapped. This process is repeated till the last element has been compared.

Python Interview Questions on Searching and Sorting chapter 14 img 10

Question 12.
Write code to implement insertion sort.
Answer:
It is very easy to implement insertion sort:
Consider a list [7,1,3,6,2,4]
Let indexi = i
indexj = indexi + 1

Python Interview Questions on Searching and Sorting chapter 14 img 11

Step 1: Define the insert_sort( ) function. It will take input ist as input.

def insertion_sort(input_list):

Step 2: for i in range(input_list)-1), set indexi =1, indexj = i+1

for i in range(len(input_list)-1):
indexi = i
indexj = i+1

Step 3: set while loop, condition inaexi>=0

  • if input_list[indexi]>input_list[indexj]
  • swap values of input list [indexi] and input_list[indexj]
  • set indexi = indexi -1
  • set indexj = indexj -1
  • else
  • set indexi = indexi -1
while indexi >= 0:
            if input list[indexi]>input
list[indexj]:
               print("swapping")
               temp = input list indexi]
               input list[indexi] = input
list[indexj]
               input list[indexj] = temp
               indexi = indexi - 1
               indexj = indexj - 1
         else:
               indexi = indexi - 1

Step 4: Print updated list

Code

def insertion_sort(input_list):
    for i in range(len(input_list)-1):
        indexi = i
        indexj = i+1
        print("indexi = ", indexi)
        print("indexj = ", indexj)
        while indexi >= 0:
              if input_list[indexi]>input_ list[indexj]:
                            print("swapping")
                            temp = input_list[indexi]
                            input_list[indexi] = input
list[indexj]
                            input_list[indexj] = temp
                            indexi = indexi - 1
                            indexj = indexj - 1
                      else :
                            indexi = indexi - 1
                 print("list update:",input_list)
        print ("final list = ", input_list)

Execution

insertion_sort([9,5,4,6,7,8,2])

Output

[7, 1, 3, 6, 2, 4 ]
indexi = 0
indexj = 1
swapping
list update: [1, 7, 3, 6, 2, 4 ]
indexi = 1
indexj = 2
swapping
list update: [1, 3, 7, 6, 2, 4 ]
indexi = 2
indexj = 3
swapping
list update: [1, 3, 6, 7, 2, 4 ]
indexi = 3
indexj = 4
swapping
swapping
swapping
list update: [ 1, 2, 3,6,7,4]
indexi = 4
indexj = 5
swapping
swapping
list update: [1, 2, 3, 4, 6, 7]
final list = [1, 2, 3, 4, 6, 7]
>>>

Shell Sort

  • Shell sort is a very efficient sorting algorithm.
  • Based on insertion sort.
  • Implements insertion sort on widely spread elements at first and then in each step space or interval is narrowed down.
  • Great for medium size data set.
  • Worst case time complexity: O(n)
  • Worst-case space complexity : 0(n)

I Consider a list: [10,30,11,4,36,31,15,1]
Size of the list, n = 8
Divide n/2 = 4, let this value be named k
Consider every kth(in this case 4th) element and sort them in the right order.

Python Interview Questions on Searching and Sorting chapter 14 img 12

II. do the following:
k = k/2 = 4/2 = 2
consider every kth element and sort the order.

Python Interview Questions on Searching and Sorting chapter 14 img 13

III. Do the following:
k = k/2 = 2/ 2 = 1
This is the last pass and will always be an insertion pass.

Python Interview Questions on Searching and Sorting chapter 14 img 14

Question 13.
Write code to implement the shell sort algorithm.
Answer:
The following steps will be involved:
Step1: Define the shell_sort( ) function to sort the list. It will take the list(input_list) that needs to be sorted as the input value.

def shell_sort(input_list):

Step2:
Calculate size, n = len(inputjist)
Number of steps for the while loop, k = n/2

def shell_sort(input_list):
n = len(input_list)
k = n//2

Step 3:

  • While k > 0:
  • for j in range 0, size of input list
  • for i in range (k, n)
  • if the value of element at i is less than the element located at index i-k, then swap the two values
  • set k = k//2
while k > 0:
     for j in range(n):
         for i in range(k,n):
             temp = input_list[i]
             if input_list[i] < input_list[i-k]:
                input_list[i] = input_list[i-k]
                input_list[i-k] = temp
    k = k//2

Step 4: Print the value of the sorted list.

Code

def shell_sort(input_list):
    n = len(input_list)
    k = n//2
    while k > 0:
         for j in range.(n) :
             for i in range(k,n):
                 temp = input_list[i]
                 if input_list[i] < input_list[i-k]:
                     input_list[i] = input_list[i-k]
                     input_list[i-k] = temp
        k = k//2
   print(input_list)

Execution

shell_sort ([10, 30, 11, 1,36, 31, 15, 4)]

Output

[1, 4, 10, 11, 15, 30, 31, 36]

Quick sort

  • In quicksort, we make use of a pivot to compare numbers.
  • All items smaller than the pivot are moved to its left side and all items larger than the pivot are moved to the right side.
  • This would provide a left partition that has all values less than the pivot and a right partition having all values greater than the pivot.
  • Let’s take a list of 9 numbers: [15, 39, 4, 20, 50, 6, 28, 2, 13].
  • The last element ‘ 13 ’ is taken as the pivot.
  • We take the first element ‘15’ as the left mark and the second last element ‘2’ as the right mark.
  • If left mark > pivot and Highmark <pivot then swap left a mark and right mark and increment left mark by 1 and decrement right make by 1.
  • If leftmark> pivot and rightmark> pivot then only decrement the right mark.
  • Same way if leftmark<pivot and rightmark< pivot then only increment the left mark.
  • If left mark <pivot and rightmark>pivot, increment leftmark by 1 and decrement right mark by 1.
  • When the left mark and right mark meet at one element, swap that element with the pivot.

I
The updated list is now [2, 6, 4, 13, 50, 39, 28, 15, 20]:

  • Take the elements to the left of 13, takin 4 as a pivot, and sort them in the same manner.
  • Once the left partition is sorted take the elements on the right and sort them taking 20 as a pivot.

Python Interview Questions on Searching and Sorting chapter 14 img 15

II.

Python Interview Questions on Searching and Sorting chapter 14 img 16

Question 14.
Write the code to implement the quicksort algorithm.
Answer:
Step: Decide upon the Pivot

  • This function takes three parameters, the list(input list), starting (fast) and ending (last) index for the list that has to be sorted.
  • Take the input_list. pivot = input_list[last]. We set the pivot to the last value of the list.
  • Set the left_pointer to first.
  • Set right_pointer to last -1, because the last element is the pivot.
  • Set pivot flag to True.
  • While pivot_flag is true:
  • If left mark > pivot and right mark <pivot then swap left mark and right mark and increment left mark by 1 and decrement right mark by 1.
  • If leftmark> pivot and rightmark> pivot then only decrement the rightmark.
  • Same way if leftmark<pivot and rightmark< pivot then only increment the leftmark.
  • If leftmark <pivot and rightmark>pivot, increment leftmark by 1 and decrement right mark by 1.
  • When left mark and rightmark meet at one element, swap that element with the pivot.
  • When, leftmark >= rightmark, swap the value of the pivot with the element at left pointer, set the pivot_flag to false.
def find_pivot (input_list, first, last):
    pivot = input_list[last]
    print("pivot =", pivot)
    left_pointer = first
    print("left pointer = ", left_pointer, " ",input_list[left_pointer])
    right_pointer = last-1
    print("right pointer = ", right_pointer, " ",input_list[right_pointer])
    pivot_flag = True

   while pivot_flag:
         if input_list[left_pointer]>pivot:
            if input_list[right_pointer]<pivot:
                temp = input_list[right_pointer]
                input_list[right_pointer]=input_ list[left_pointer]

                input_list[left_pointer]= temp
                right_pointer = right_pointer-1
                left_pointer = left_pointer+1

       else:
                right_pointer = right_pointer-1
  else:
        left_pointer = left_pointer+1
        right_pointer = right_pointer-1
  if left_pointer >= right_pointer:
        temp = input_list[last]
  input_list[last] = input_list[left_pointer]
  input_list[left_pointer] = temp
  pivot_flag = False
print(left_pointer)
return left_pointer

Step 2:
Define quicksort(input list) function.

  • This function will take a list as input.
  • Decides the starting point(O) and end point(length_of_the_list-1) for sorting.
  • Call the qsHelper( ) function.
def quicksort(input_list):
    first = 0
    last = len(input_list)-1
    qsHelper (input_list,first, last)

Step 3:
Define the qsHelper( ) function

This function checks the first index and last index value, it is a recursive function, it calls the find_pivot method where left mark is incremented by 1 and the right mark is decremented by 1. So, as long as the left mark(which is parameter first in this case) is less than the right mark(which is parameter last in this case) the while loop will be executed where qsHelper finds a new value of pivot, creates; eft and right partition and calls itself.

def qsHelper (input_list,first, last) :
    if first<last:
         partition = find_pivot (input_ list, first, last)
         qsHelper(input_list, first,partition-1)
         qsHelper(input_list,partition+l,last)

Code

def find_pivot (input_list, first, last):
    pivot = input_list[last]
    left_pointer = first
    right_pointer = last-1
    pivot_flag = True

    while pivot_flag:
          if input_list[left_pointer]>pivot:
             if input_list[right_pointer]<pivot:
                temp = input_list[right_pointer]
                input_list[right_pointer]=input_ list[left_pointer]
                input_list[left_pointer]= temp
                right_pointer = right_pointer-l left_pointer = left_pointer+l 
        else:
                right_pointer = right_pointer-l
        else:
               if input_list[right_pointer]<pivot:
                 left_pointer = left_pointer+l 
              else:
                 left_pointer = left_pointer+l 
                 right_pointer = right_pointer-1
            if left_pointer >= right_pointer: 
            temp = input_list[last]
            input_list[last] = input_list[left_pointer]

            input_list[left_pointer] = temp 
            pivot_flag = False 
            return left_pointer 
def quicksort(input_list): 
first = 0 
last = len(input_list)-1 
qsHelper (input_list, first, last)
def qsHelper (input_list,first, last) : 
if firstclast:
partition = find_pivot (input_list,first, last) 
qsHelper (input_list, first, partition-1) 
qsHelper(input_list,partition+1,last)

Execution

input_list=[15,39,4,20, 50, 6,28,2, 13]
quicksort(input_list)
print(input list)

Output

[2,4, 6, 13, 15, 20, 28, 39, 50]