import os
from time import time
class Node: #Declaración de variables para crear los nodos
probability =0.0 #Declarada como fload
symbol = " " #Variable vacia
encodings = ""
visited = False #variable Boolean
parent = -1 #Longitud de 0 a -1 variable entera
class Huffman: #Declaración de variables para la creación del arbol de Huffman
Tree = None #Retornar arbol
Root = None #Retornar raiz
Nodes = []
probs = {} #bloque, instancia el método
dictEncoder = {}
#1
def __init__(self,symbols): #Inicianilizamos las funciones, con los atributos que va a utilizar
self.initNodes(symbols) #retorna valores
self.buildTree()
self.buildDictionary()
#2
def initNodes(self,probs): #creamos los nodos con sus respectivas posibilidades
for symbol in probs:
node =Node() #inicializamos el node
node.symbol = symbol
node.probability = probs[symbol] # Asiganamos una probabilidad a cada simbolo o letra
node.visited = False #Variable que no es fija que va a ir cambiando
self.Nodes.append(node) #creamos una lista para cada nodo creado
self.probs[symbol]=probs[symbol] #Establece para ca probabilidad de simbolo
#3
def buildTree(self): #Realizamos las operaciones de acuerdo a la lógica de Huffman
indexMin1 = self.getNodeWithMinimumProb() #buscamos el menor número de la primera probabilidad
indexMin2 = self.getNodeWithMinimumProb() #buscamos el menor número de la segunda probabilidad
while indexMin1 != -1 and indexMin2 !=-1: #(!= evalua como verdadero si 2 variable son diferentes)
node =Node()
node.symbol="." # se llama el simbolo digitado para que salga el resultado
node.encodings=""
#llamamos a las dos probabilidades minimas
prob1 = self.Nodes[indexMin1].probability
prob2 = self.Nodes[indexMin2].probability
node.probability = prob1 + prob2
node.visited =False #false =1
node.parent = -1 #restamos la probabilidad a -1
self.Nodes.append(node)
self.Nodes[indexMin1].parent = len(self.Nodes) - 1 #lista o cadena que queremos medir
self.Nodes[indexMin2].parent = len(self.Nodes) - 1
#Regla: 0 a mayor probabilidad, 1 a menor probalidad
if prob1 >= prob2:
self.Nodes[indexMin1].encoding = "0"
self.Nodes[indexMin2].encoding = "1"
else:
self.Nodes[indexMin1].encoding = "1"
self.Nodes[indexMin2].encoding = "0"
indexMin1 = self.getNodeWithMinimumProb()
indexMin2 = self.getNodeWithMinimumProb()
#4
def getNodeWithMinimumProb(self):
minProb = 1.0
indexMin = -1
for index in range(0, len(self.Nodes)):
if (self.Nodes[index].probability) < minProb and (not self.Nodes[index].visited):
minProb = self.Nodes[index].probability
indexMin = index
if indexMin != -1:
self.Nodes[indexMin].visited = True
return indexMin
#5
def showSymbolEncoding(self, symbol):
found = False
index = 0
encoding = ""
for i in range(0, len(self.Nodes)):
if self.Nodes[i].symbol ==symbol:
found = True
index = i
break
if found:
while index != -1:
encoding = "%s%s" % (self.Nodes[index].encoding, encoding)
index = self.Nodes[index].parent
else:
encoding = "simbolo desconocido"
return encoding
# 6
def buildDictionary(self): # Creacion de diccionaio, se guardan los simbolos con sus respectivos
# codigos binarios resueltos por el arbol
for symbol in self.probs:
encoding = self.showSymbolEncoding(symbol)
self.dictEncoder[symbol] = encoding
# 7
def encode(self, plain): #Agrupa los codigos binarios codificados de acuerdo al mensaje escrito
#en la consola
encoded =""
for symbol in plain:
encoded = "%s%s" % (encoded, self.dictEncoder[symbol])
return encoded
# Inicio de la decodificacion
def decode(self, encoded): # Recibe la cadena del codigo binario
index = 0
decoded = ""
while index < len(encoded):
found = False
#Busca cada en parte codificada un simbolo, buscando cuál es compatible
#con otra
aux = encoded[index:]
for symbol in self.probs:
if aux.startswith(self.dictEncoder[symbol]):
decoded = "%s%s" % (decoded, symbol)
index = index + len(self.dictEncoder[symbol])
break
return decoded
#Fin
if __name__ == "__main__":
print ("\n\n............CODIFICACION........\n\n")
mensaje =input("Ingrese la palabra u oracion: ")
print ("\n\nTotal de simbolos: \n\n %s"% (len(mensaje)))
simbolos=''
probabilidad=[]
msm=mensaje
d=0
for i in mensaje:
if i in msm:
simbolos+=i
probabilidad.append(float(float ( msm.count(i))/float(len(mensaje))))
msm=msm.replace(i, '')
d+= 1
symbols=dict(zip(simbolos, probabilidad)) #Funcion para llamar al simbolo y a su probabilidad
print ("\n\nSimbolos comprimidos: \n\n" ,d) #Imprime la cantidad de simbolos que contabilizalo la funcion count
print ("\n\nPROBABILIDAD DE CADA SIMBOLO:\n\n" , symbols)
tiempo_inicial=time() #Funcion para determinar el tiempo del programa
#Codificacion de los simbolos
huffman=Huffman(symbols) #Llamamos a la clase Huffman
print ("\n\nSimbolos codificados usando el arbol de Huffman: \n\n")
for symbol in symbols:
print ("Simbolo: %s; Codificacion: %s" % (symbol, huffman.showSymbolEncoding(symbol)))
encoded = huffman.encode(mensaje) #Llama funcion tras funcion para el procedimiento de codificacion
print ("\n\nMensaje que se esta codificando: \n\n%s" % (mensaje))
print ("\n\nCodificacion en bits : \n\n%s" % (encoded)) #Notamos el msj en bits
print ("\n\nLa longitud de codigo binario es: \n\n%s" % (len(encoded)))
data = encoded
#Decodificacion
print ("\n\n..................DECODIFICACION..................\n\n")
decoded = huffman.decode(data) #Llamamos a las funciones correspondientes y el mensaje llamado data
print ("El codigo binario a decodificar es:\n\n", data )
print ("\n\nEl mensaje decodificando es: \n\n %s" % (decoded)) #Imprimimos el resultado de la funcion decoded
#Calculo para el tiempo del procedimiento
tiempo_final= time()
tiempo_ejecucion= tiempo_final - tiempo_inicial
print ('\n\nEl tiempo de transmision es: ',tiempo_ejecucion)
os._exit(0)