#====================================================================== # CSCI 1020, Sorting-by-reversals Lab # # Your name(s): # #====================================================================== # # You must implement the following functions in order for the entire # program to work properly. By default, when executing this program # it will run a random experiment with 25 characters, using an initial # shuffle with 15 reversals (though it might be that fewer that 15 reversals # will be needed to fix the sequence). # # For a test that triggers use of find_increasing_strip, try running function # experiment(25,15,8) # # For a more general test with sequence of length n, and using r initial reversals, call # experiment(n, r) def perform_reversal(data, a, b): """Return a new sequence that reflects inverting the portion of data from indices a to b, inclusive. """ def count_breakpoints(data): """Return the current number of breakpoints for the given sequence.""" def count_breakpoints_fixed(data, a, b): """Return the net number of breakpoints that are resolved if performing a reversal [a,b]. For example, returning +1 means that one existing breakpoint would disappear with a reversal.""" def find_increasing_strip(data): """Return [a,b] defining the second increasing strip (presuming there are two or more such strips).""" #====================================================================== # Do not change below this line #====================================================================== import sys import random def find_best_reversal(data): """Return [a,b] that represents a reversal that would resolve the greatest number of breakpoints.""" best = 0 bestA,bestB = -1, -1 for a in range(1,len(data)-2): for b in range(1+a,len(data)-1): temp = count_breakpoints_fixed(data,a,b) if temp > best: best = temp bestA = a bestB = b return bestA,bestB def solve(data): """Convert original data back to the identity, and return the number of reversal steps that were used.""" reversals = 0 bp = count_breakpoints(data) while bp != 0: a,b = find_best_reversal(data) if a == -1: best = 0 else: best = count_breakpoints_fixed(data,a,b) if best <= 0: # did not find way to reduce breakpoints a,b = find_increasing_strip(data) # reverse an increasing strip instead print('Able to remove %d breakpoint%s' % (best, '' if best==1 else 's')) data = verbose_reversal(data, a, b) bp -= best actual = count_breakpoints(data) if actual != bp: print("WARNING: error detected") reversals += 1 return reversals def display(seq, a=None, b=None): """Display given sequence with indices, highlight range [a,b] if specified.""" n = len(seq) if a is None: a = 0 if b is None: b = a-1 print(' k: ' + ' '.join('%2d'%val for val in range(n))) print(' ' + '---'*a + '='*(3*(1+b-a)-1) + '---'*(n-b-1)) print('data[k]: ' + ' '.join('%2d'%val for val in seq)) bp = count_breakpoints(seq) print('There are %s breakpoints in this pattern' % ('?' if bp is None else str(bp))) print('') def verbose_reversal(seq, a, b): """Perform the reversal, and annotate the result.""" seq = perform_reversal(seq, a, b) print('performing inversion for a=%d, b=%d results in' % (a,b)) display(seq,a,b) return seq def make_random(n, k, seed=None): """Make a random instance with numbers 0 to n-1, such that 0 remains at the left and n-1 remains at the far right. n should be at least 4. Seed for random number generator is optional. """ random.seed(seed) print('Creating initial random pattern:') seq = list(range(n)) for j in range(k): # do a single reversal a = random.randint(1,n-3) b = random.randint(a+1,n-2) seq = verbose_reversal(seq, a, b) return seq def experiment(n,r,seed): """Perform an experiment for sequence of length n using r initial reversals.""" data = make_random(n,r,seed) print('') print('='*30) print('Time to solve...') count = solve(data) print('Used %d reversals' % count) if __name__ == '__main__': seed = None if len(sys.argv) > 1: seed = int(sys.argv[1]) experiment(25,15,seed)