Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- import random
- import string
- from math import comb
- from timeit import default_timer as timer
- def main(TEST = False, HARDCORE_MODE = False):
- '''
- Η σημαία «TEST» είναι χρήσιμη για την φόρτωση των ενδεικτικών αλφαριθμητικών - κουπονιών που δίνονται
- στην εκφώνηση.
- True -> ενδεικτικά κουπόνια
- False -> ψευδοτυχαία κουπόνια
- H σημαία «HARDCORE MODE» είναι αληθής για την υλοποίηση του κατακερματισμού με τη χρήση της ιδιόχειρης
- συνάρτησης κατακερσματισμού. Όταν είναι ψευδής, αξιοποιείται η hash(), εγγενής της Python.
- ΩΣ ΠΡΟΣ ΑΞΙΟΛΟΓΗΣΗ ΔΙΑΤΙΘΕΤΑΙ ΤΟ ΠΡΟΓΡΑΜΜΑ ΜΕ ΕΠΙΛΟΓΗ HARDCORE_MODE = False.
- '''
- timeElapsed = []
- if TEST:
- run(10, TEST, HARDCORE_MODE)
- else:
- for i in range(1, 6):
- timeElapsed.append(run(10**i, TEST, HARDCORE_MODE))
- def run(cases, TEST, HARDCORE_MODE):
- coupons = CouponGenerator(cases)
- coupons.generate(TEST)
- coupons.array.sort()
- start = timer()
- codes = coupons.array
- variants = tableVariants(codes)
- tabletablesize = nextPrime(len(variants))
- HT = HashTable(tabletablesize)
- for variant in variants:
- HT.insert(variant, HARDCORE_MODE)
- pairs = HT.searchForPairs()
- end = timer()
- print("There are {} similar pairs. Took {} seconds for the {} cases.".format(pairs, end-start, cases))
- return end-start
- class HashTable:
- def __init__(self, tablesize):
- self.tablesize = tablesize
- self.table = [[] for _ in range(tablesize)]
- def searchForPairs(self):
- counter = 0
- for bucket in self.table:
- for item in bucket:
- if item[1] > 1:
- counter += comb(item[1], 2)
- '''
- Bottleneck στην υλοποίηση αυτή σίγουρα αποτελεί η συνάρτηση math.comb που
- έχει μεγάλη πολυπλοκότητα χρόνου.
- '''
- return counter
- def insert(self, code, HARDCORE_MODE = False):
- if HARDCORE_MODE == False:
- codeNum = hash("".join(code)) % self.tablesize
- else:
- constant = 137
- codeNum = str2char(code)
- lastHashValue = 0
- p_pow = 1
- for character in codeNum:
- if character == "*":
- lastHashValue = ((ord('0') + 1) * p_pow + lastHashValue) % self.tablesize
- else:
- lastHashValue = ((ord(character) + 1) * p_pow + lastHashValue) % self.tablesize
- p_pow = (p_pow * constant) % self.tablesize
- codeNum = lastHashValue
- for item in self.table[codeNum]:
- if item[0] == code:
- item[1] += 1
- return
- self.table[codeNum].append([code, 1])
- def tableVariants(codes):
- '''
- Παράγει και επιστρέφει μία λίστα που περιέχει κάθε υπο-αλφαριθμητικό με την προσθήκη αστερίσκου
- σε κάθε αντικαθιστούμενο σύμβολο.
- '''
- table = []
- for h in range(len(codes)):
- string = codes[h]
- for i in range(0, len(string)):
- table.append(string[0:i] + "*" + string[i+1:len(string)])
- return table
- def printTable(table):
- '''
- Για dev λόγους. Τυπώνει όμορφα τον πίνακα.
- '''
- for row in table:
- for col in row:
- print(col, end="\t")
- print("\n")
- class CouponGenerator:
- def __init__(self, n):
- self.array = []
- self.n = n
- def printArray(self):
- for i in self.array:
- print(i)
- def generate(self, TEST = False):
- if TEST:
- self.array = ['WELC1234OTHE', 'IEEE1234MEXZ', 'AAAA0000ACAD', 'AAAA0000ACAF', 'AAAA0000ACAB', 'AAAA0000ABAB']
- else:
- for _ in range(self.n):
- 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)))))
- print(self.n, "coupons generated.")
- def str2num(code):
- '''Δέχεται ως όρισμα μία ακολουθία δεδομένων και την μετατρέπει
- σε λίστα τύπου ακέραιου'''
- numCode = []
- for character in code:
- if ord(character) >=65 and ord(character) <= 90:
- numCode.append(ord(character)-54)
- else:
- if character == "*":
- continue
- numCode.append(int(character))
- return numCode
- def str2char(code):
- '''Δέχεται ως όρισμα μία ακολουθία δεδομένων και την μετατρέπει
- σε λίστα τύπου χαρακτήρα'''
- numCode = []
- for character in code:
- numCode.append(character)
- return numCode
- def nextPrime(n):
- '''
- Υπολογίζει αποδοτικά τον επόμενο πρώτο αριθμό δεδομένου ενός που δίνεται ως όρισμα.
- '''
- notPrime = []
- isPrime = []
- for i in range (n+1, n+200):
- notPrime.append(i)
- for j in notPrime:
- prime = True
- for x in range(2, j-1):
- if j % x == 0:
- prime = False
- break
- if prime:
- isPrime.append(j)
- return min(isPrime)
- if __name__ == "__main__":
- print("Testing with native hash():")
- main(False, False)
- print("\nTesting with homemade hash function:")
- main(False, True)
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement