简体   繁体   中英

Errors arises when implement merge sort in python

I'm trying to implement merge sort in python as following:

def MergeSortTopdown(list_n):
     #Base condition to stop recursion
    if len(list_n) == 1:
        return list_n
    else:
        mid = int(len(list_n)/2)
        first_half = list_n[:mid]
        second_half = list_n[mid:]
        MergeSortTopdown(first_half)
        MergeSortTopdown(second_half)
        i = 0
        j = 0 
        n = len(list_n)
        for k in range(n):
            if j >= len(first_half) and i < len(second_half):
                list_n[k] = first_half[i]
                i += 1 
            if i >= len(first_half) and j < len(second_half): 
                list_n[k] = second_half[j]
                j += 1
            if i < len(first_half) and j < len(second_half):
                if first_half[i] > second_half[j]:
                    list_n[k] = second_half[j]
                    j += 1   
                elif second_half[j] > first_half[i]:
                    list_n[k] = first_half[i]
                    i += 1
                elif second_half[i] == first_half[j]:
                    list_n[k] = first_half[i]
                    if i>j:
                        i += 1
                    else:
                        j += 1

    return list_n

it seems reasonable when I tested with already sorted list. However, when I run, this error raises:

MergeSortTopdown([3,4,6,7,1,8,56,112,67])
Traceback (most recent call last):

  File "<ipython-input-11-29db640f4fc6>", line 1, in <module>
    MergeSortTopdown([3,4,6,7,1,8,56,112,67])

  File "C:/Users/Emmanuel Hoang/MergeSortTopDown.py", line 13, in MergeSortTopdown
    MergeSortTopdown(second_half)

  File "C:/Users/Emmanuel Hoang/MergeSortTopDown.py", line 13, in MergeSortTopdown
    MergeSortTopdown(second_half)

  File "C:/Users/Emmanuel Hoang/MergeSortTopDown.py", line 19, in MergeSortTopdown
    list_n[k] = first_half[i]

IndexError: list index out of range

Can you tell me what's wrong with my code, is there any way that I can improve my code. Thank you in advance

You've tried to reference an element past the end of the list. I added some straightforward print statements to your code:

   for k in range(n):
        print("LOOP TOP", k, first_half, second_half, list_n)
        if j >= len(first_half) and i < len(second_half):
            print("TRACE", list_n, k, "\t", first_half, i)
            list_n[k] = first_half[i]
            i += 1

Then I shortened the input list to [8,56,112,3,67] .

Output:

LOOP TOP 0 [8] [56] [8, 56]
LOOP TOP 1 [8] [56] [8, 56]
LOOP TOP 0 [3] [67] [3, 67]
LOOP TOP 1 [3] [67] [3, 67]
LOOP TOP 0 [112] [3, 67] [112, 3, 67]
LOOP TOP 1 [112] [3, 67] [3, 3, 67]
TRACE [3, 3, 67] 1   [112] 0
LOOP TOP 2 [112] [3, 67] [3, 67, 67]
TRACE [3, 67, 67] 2      [112] 1

This is followed by the crash you got. You try to fetch first_half[1] when there's only an element 0.

ANALYSIS

You have three successive if statements to check list bounds:

        if j >= len(first_half) and i < len(second_half):
        if i >= len(first_half) and j < len(second_half): 
        if i < len(first_half) and j < len(second_half):

You have i and j switched in the first check: i is the first_half subscript. This change fixes the merge:

        if i < len(first_half) and j >= len(second_half):

Suggestions

Part of your problem is that your merge logic is too complex. You have a single value check during the main part of the loop: move the lower of the list heads to the merged list. Do this while both indices are in range.

Then, when one index hits the end of its list, drop out of the loop and add the remaining elements of the other list. Use the extend method. So ...

while i < len(first_half) and j < len(second_half):
    if first_half[i] < second_half[j]:
        # move smaller element to list_n;
        # increment i or j as needed
    k += 1

# One of these will be an empty operation.
list_n.extend(first_half[i:])
list_n.extend(second_half[j:])

To resolve the IndexError :

The first case that you check for in your 'merge step' of the merge sort -- if you have already merged all elements from the list second_half -- has the names of your two lists first_half and second_half switched around. Instead of this:

if j >= len(first_half) and i < len(second_half):
    list_n[k] = first_half[i]
    i += 1 

you should have this:

if j >= len(second_half) and i < len(first_half):
    list_n[k] = first_half[i]
    i += 1

This will correctly check for the condition specified above.

Why this was happening:

The reason why you received an IndexError is because you were trying to call first_half[i] and were not correctly confirming that i was a valid index in the list first_half before doing so.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM