Advertisement
tsounakis

Algorithms #2 (Severe pain)

Apr 22nd, 2022
1,008
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 6.10 KB | None | 0 0
  1. import random
  2. import string
  3. from math import comb
  4. from timeit import default_timer as timer
  5.  
  6. def main(TEST = False, HARDCORE_MODE = False):
  7.     '''
  8.        Η σημαία «TEST» είναι χρήσιμη για την φόρτωση των ενδεικτικών αλφαριθμητικών - κουπονιών που δίνονται
  9.        στην εκφώνηση.
  10.        True -> ενδεικτικά κουπόνια
  11.        False -> ψευδοτυχαία κουπόνια
  12.  
  13.        H σημαία «HARDCORE MODE» είναι αληθής για την υλοποίηση του κατακερματισμού με τη χρήση της ιδιόχειρης
  14.        συνάρτησης κατακερσματισμού. Όταν είναι ψευδής, αξιοποιείται η hash(), εγγενής της Python.
  15.  
  16.        ΩΣ ΠΡΟΣ ΑΞΙΟΛΟΓΗΣΗ ΔΙΑΤΙΘΕΤΑΙ ΤΟ ΠΡΟΓΡΑΜΜΑ ΜΕ ΕΠΙΛΟΓΗ HARDCORE_MODE = False.
  17.    '''
  18.     timeElapsed = []
  19.     if TEST:
  20.         run(10, TEST, HARDCORE_MODE)
  21.     else:
  22.         for i in range(1, 6):
  23.             timeElapsed.append(run(10**i, TEST, HARDCORE_MODE))
  24.  
  25. def run(cases, TEST, HARDCORE_MODE):
  26.     coupons = CouponGenerator(cases)
  27.     coupons.generate(TEST)
  28.     coupons.array.sort()
  29.  
  30.     start = timer()
  31.     codes = coupons.array
  32.  
  33.     variants = tableVariants(codes)
  34.     tabletablesize = nextPrime(len(variants))
  35.  
  36.     HT = HashTable(tabletablesize)
  37.    
  38.     for variant in variants:
  39.         HT.insert(variant, HARDCORE_MODE)
  40.  
  41.     pairs = HT.searchForPairs()
  42.  
  43.     end = timer()
  44.     print("There are {} similar pairs. Took {} seconds for the {} cases.".format(pairs, end-start, cases))
  45.     return end-start
  46.  
  47. class HashTable:
  48.     def __init__(self, tablesize):
  49.         self.tablesize = tablesize
  50.         self.table = [[] for _ in range(tablesize)]
  51.  
  52.     def searchForPairs(self):
  53.         counter = 0
  54.         for bucket in self.table:
  55.             for item in bucket:
  56.                 if item[1] > 1:
  57.                     counter += comb(item[1], 2)
  58.                     '''
  59.                        Bottleneck στην υλοποίηση αυτή σίγουρα αποτελεί η συνάρτηση math.comb που
  60.                        έχει μεγάλη πολυπλοκότητα χρόνου.
  61.                    '''
  62.         return counter
  63.  
  64.     def insert(self, code, HARDCORE_MODE = False):
  65.         if HARDCORE_MODE == False:
  66.             codeNum = hash("".join(code)) % self.tablesize
  67.         else:
  68.             constant = 137
  69.             codeNum = str2char(code)
  70.             lastHashValue = 0
  71.             p_pow = 1
  72.  
  73.             for character in codeNum:
  74.                 if character == "*":
  75.                     lastHashValue = ((ord('0') + 1) * p_pow + lastHashValue) % self.tablesize
  76.                 else:
  77.                     lastHashValue = ((ord(character) + 1) * p_pow + lastHashValue) % self.tablesize
  78.                     p_pow = (p_pow * constant) % self.tablesize
  79.             codeNum = lastHashValue
  80.         for item in self.table[codeNum]:
  81.             if item[0] == code:
  82.                 item[1] += 1
  83.                 return
  84.         self.table[codeNum].append([code, 1])
  85.        
  86. def tableVariants(codes):
  87.     '''
  88.        Παράγει και επιστρέφει μία λίστα που περιέχει κάθε υπο-αλφαριθμητικό με την προσθήκη αστερίσκου
  89.        σε κάθε αντικαθιστούμενο σύμβολο.
  90.    '''
  91.     table = []
  92.     for h in range(len(codes)):
  93.         string = codes[h]
  94.         for i in range(0, len(string)):
  95.             table.append(string[0:i] + "*" + string[i+1:len(string)])  
  96.     return table  
  97.  
  98. def printTable(table):
  99.     '''
  100.        Για dev λόγους. Τυπώνει όμορφα τον πίνακα.
  101.    '''
  102.     for row in table:
  103.         for col in row:
  104.             print(col, end="\t")
  105.         print("\n")
  106.  
  107. class CouponGenerator:
  108.     def __init__(self, n):
  109.         self.array = []
  110.         self.n = n
  111.     def printArray(self):
  112.         for i in self.array:
  113.             print(i)
  114.     def generate(self, TEST = False):
  115.         if TEST:
  116.             self.array = ['WELC1234OTHE', 'IEEE1234MEXZ', 'AAAA0000ACAD', 'AAAA0000ACAF', 'AAAA0000ACAB', 'AAAA0000ABAB']
  117.         else:
  118.             for _ in range(self.n):
  119.                 self.array.append(''.join((''.join(random.SystemRandom().choice(string.ascii_uppercase) for _ in range(4)),''.join(random.SystemRandom().choice(string.digits) for _ in range(4)),''.join(random.SystemRandom().choice(string.ascii_uppercase) for _ in range(4)))))
  120.         print(self.n, "coupons generated.")
  121.  
  122. def str2num(code):
  123.     '''Δέχεται ως όρισμα μία ακολουθία δεδομένων και την μετατρέπει
  124.    σε λίστα τύπου ακέραιου'''
  125.     numCode = []
  126.     for character in code:
  127.         if ord(character) >=65 and ord(character) <= 90:
  128.             numCode.append(ord(character)-54)
  129.         else:
  130.             if character == "*":
  131.                 continue
  132.             numCode.append(int(character))
  133.     return numCode
  134.    
  135. def str2char(code):
  136.     '''Δέχεται ως όρισμα μία ακολουθία δεδομένων και την μετατρέπει
  137.    σε λίστα τύπου χαρακτήρα'''
  138.     numCode = []
  139.     for character in code:
  140.         numCode.append(character)
  141.     return numCode
  142.  
  143. def nextPrime(n):
  144.     '''
  145.        Υπολογίζει αποδοτικά τον επόμενο πρώτο αριθμό δεδομένου ενός που δίνεται ως όρισμα.
  146.    '''
  147.     notPrime = []
  148.     isPrime = []
  149.     for i in range (n+1, n+200):
  150.         notPrime.append(i)
  151.     for j in notPrime:
  152.         prime = True
  153.         for x in range(2, j-1):
  154.             if j % x == 0:
  155.                 prime = False
  156.                 break
  157.         if prime:
  158.             isPrime.append(j)
  159.     return min(isPrime)
  160.  
  161. if __name__ == "__main__":
  162.     print("Testing with native hash():")
  163.     main(False, False)
  164.     print("\nTesting with homemade hash function:")
  165.     main(False, True)
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement