MAP (ассоциативный контейнер или словарь)
Реализация MAP , ассоциативного контейнера или чаще известного как словарь. Реализован на основе AVL дерева.
Платформы: Windows, Linux
'\\\\\\\\\\\\\\\\\\\\\\\\\ руководство по использованию \\\\\\\\\\\\\\\\\\\\\\\' 'для создания ассоциативного контейнера необходимо выполнить макрос: 'MapCreate(MapPTR , MapTypeKey , MapTypeData , MapReplaceDataFlag) '-------MapPTR - любое уникальное имя , будущий указатель (с помощью его происходит доступ ко всему интерфейсу) '-------MapTypeKey - тип данных для ключа (Byte , String и другие) , по которому происходит вставка\поиск\удаление в MAP '-------MapTypeData - тип для самих данных (Byte , String и другие) '-------MapReplaceDataFlag - необязательный флаг для перезаписи данных по уже имеющемуся ключу (если не указывать параметр или 0 , то не перезаписывать, если 1 - перезаписывать ) 'После выполнения макроса , можно: '1) выполнять вставку с помощью INSERT: 'INSERT (KEY , DATA) '-------KEY - уникальный ключ , имеющий тип , указанный в MapTypeKey '-------DATA - любые данные , имеющие тип , указанный в MapTypeData '2) удалять один элемент с помощью DELETENODE: 'DELETENODE(KEY) '-------KEY - уникальный ключ , имеющий тип , указанный в MapTypeKey '3) искать и получать данные с помощью FIND: 'FIND(KEY) '-------KEY - уникальный ключ , имеющий тип , указанный в MapTypeKey '4) Удалить все данные из MAP с помощью DeleteTree: 'DeleteTree() '--------------------------------------- 'Далее идут малозначимые и малопригодные возможности и функции '-------------------------------------- ' '5) можно получить указатель на текущий корень дерева, примерно так: ' 'MapPTR->pRoot ' '6) узнать высоту дерева можно примерно так: ' 'MapPTR->GetTreeHeight(MapPTR->pRoot) ' '7) можно распечатать в консоли все ключи и данные с помощью InOrder: 'InOrder(MapPTR->pRoot) '8) можно распечатать псевдографический вид дерева с помощью printTreePseudographic (дерево повернуто на бок): 'printTreePseudographic(MapPTR->pRoot) 'пример можно найти в самом внизу ' Реализация MAP с помощью AVL дерева #MACRO map_type (ctkey , ctdata , MapReplaceDataFlag...) #IFNDEF container_type_key##ctkey Type container_type_key##ctkey As ctkey #ENDIF #IFNDEF Type container_type_data##ctdata As ctdata #ENDIF #IFNDEF Node##ctkey##ctdata Type Node##ctkey##ctdata #IF ctkey = String As Zstring Ptr nKey #ELSE As container_type_key##ctkey nKey #ENDIF #IF ctdata = String As Zstring Ptr nData #ELSE As container_type_data##ctdata nData #ENDIF As Node##ctkey##ctdata Ptr pLeft As Node##ctkey##ctdata Ptr pRight As Byte bHeight End Type #ENDIF #IFNDEF Tmap##ctkey##ctdata Type Tmap##ctkey##ctdata As Node##ctkey##ctdata Ptr pRoot As Byte bFlagDelete Declare Function Max( a As Byte, b As Byte) As Byte Declare Function GetTreeHeight(pNode As Node##ctkey##ctdata Ptr) As Byte Declare Function RightRotate(y As Node##ctkey##ctdata Ptr) As Node##ctkey##ctdata Ptr Declare Function LeftRotate(x As Node##ctkey##ctdata Ptr) As Node##ctkey##ctdata Ptr Declare Function GetBalance(pNode As Node##ctkey##ctdata Ptr) As Byte Declare Function InsertNode(pNode As Node##ctkey##ctdata Ptr, nKey As container_type_key##ctkey , nData As container_type_data##ctdata) As Node##ctkey##ctdata Ptr Declare Function GetMinNode(pNode As Node##ctkey##ctdata Ptr) As Node##ctkey##ctdata Ptr Declare Function DelNode(pRoot As Node##ctkey##ctdata Ptr, nKey As container_type_key##ctkey) As Node##ctkey##ctdata Ptr #IF ctdata = String Declare Function FindNode(pNode As Node##ctkey##ctdata Ptr , nKey As container_type_key##ctkey) As Zstring Ptr #ELSE Declare Function FindNode(pNode As Node##ctkey##ctdata Ptr , nKey As container_type_key##ctkey) As container_type_data##ctdata #ENDIF Declare Sub DelTree(pRoot As Node##ctkey##ctdata Ptr) ' user interface Declare Sub Insert(nKey As container_type_key##ctkey , nData As container_type_data##ctdata) Declare Sub DeleteNode(nKey As container_type_key##ctkey) Declare Function Find(nKey As container_type_key##ctkey) As container_type_data##ctdata Declare Sub DeleteTree() End Type Dim Shared As Byte m_gg_m##ctkey##ctdata(MapReplaceDataFlag) Function Tmap##ctkey##ctdata.Max( a As Byte, b As Byte) As Byte Return Iif(a > b , a , b) End Function Function Tmap##ctkey##ctdata.GetTreeHeight(pNode As Node##ctkey##ctdata Ptr) As Byte If pNode = 0 Then Return 0 Return pNode->bHeight End Function Function Tmap##ctkey##ctdata.RightRotate(y As Node##ctkey##ctdata Ptr) As Node##ctkey##ctdata Ptr Dim As Node##ctkey##ctdata Ptr x = y->pLeft Dim As Node##ctkey##ctdata Ptr z = x->pRight x->pRight = y y->pLeft = z y->bHeight = Max(GetTreeHeight(y->pLeft), GetTreeHeight(y->pRight)) + 1 x->bHeight = Max(GetTreeHeight(x->pLeft), GetTreeHeight(x->pRight)) + 1 Return x End Function Function Tmap##ctkey##ctdata.LeftRotate(x As Node##ctkey##ctdata Ptr) As Node##ctkey##ctdata Ptr Dim As Node##ctkey##ctdata Ptr y = x->pRight Dim As Node##ctkey##ctdata Ptr z = y->pLeft y->pLeft = x x->pRight = z x->bHeight = Max(GetTreeHeight(x->pLeft), GetTreeHeight(x->pRight)) + 1 y->bHeight = Max(GetTreeHeight(y->pLeft), GetTreeHeight(y->pRight)) + 1 Return y End Function Function Tmap##ctkey##ctdata.GetBalance(pNode As Node##ctkey##ctdata Ptr) As Byte If pNode = 0 Then Return 0 Return GetTreeHeight(pNode->pLeft) - GetTreeHeight(pNode->pRight) End Function Function Tmap##ctkey##ctdata.InsertNode(pNode As Node##ctkey##ctdata Ptr, nKey As container_type_key##ctkey , nData As container_type_data##ctdata) As Node##ctkey##ctdata Ptr If pNode = 0 Then Dim As Node##ctkey##ctdata Ptr pNode = New Node##ctkey##ctdata #IF ctkey = String Dim As Zstring Ptr pszTemp = Callocate(Len(nData)+1) *pszTemp = nKey pNode->nKey = pszTemp #ELSE pNode->nKey = nKey #ENDIF #IF ctdata = String Dim As Zstring Ptr pszTemp2 = Callocate(Len(nData)+1) *pszTemp2 = nData pNode->nData = pszTemp2 #ELSE pNode->nData = nData #ENDIF pNode->pLeft = 0 pNode->pRight = 0 pNode->bHeight = 1 Return pNode Endif #IF ctkey = String If nKey < *(pNode->nKey) Then pNode->pLeft = InsertNode(pNode->pLeft, nKey , nData) Elseif nKey > *(pNode->nKey) Then pNode->pRight = InsertNode(pNode->pRight, nKey , nData) Else Select Case Ubound(m_gg_m##ctkey##ctdata) Case 1 #IF ctdata = String *(pNode->nData) = nData #ELSE pNode->nData = nData #ENDIF End Select Return pNode Endif pNode->bHeight = 1 + Max(GetTreeHeight(pNode->pLeft), GetTreeHeight(pNode->pRight)) Dim As Byte bBalance = GetBalance(pNode) If bBalance > 1 andalso nKey < *(pNode->pLeft->nKey) Then Return RightRotate(pNode) If bBalance < -1 andalso nKey > *(pNode->pRight->nKey) Then Return LeftRotate(pNode) If bBalance > 1 andalso nKey > *(pNode->pLeft->nKey) Then pNode->pLeft = LeftRotate(pNode->pLeft) Return RightRotate(pNode) Endif If bBalance < -1 andalso nKey < *(pNode->pRight->nKey) Then pNode->pRight = RightRotate(pNode->pRight) Return LeftRotate(pNode) Endif #ELSE If nKey < pNode->nKey Then pNode->pLeft = InsertNode(pNode->pLeft, nKey , nData) Elseif nKey > pNode->nKey Then pNode->pRight = InsertNode(pNode->pRight, nKey , nData) Else Select Case Ubound(m_gg_m##ctkey##ctdata) Case 1 #IF ctdata = String *(pNode->nData) = nData #ELSE pNode->nData = nData #ENDIF End Select Return pNode Endif pNode->bHeight = 1 + Max(GetTreeHeight(pNode->pLeft), GetTreeHeight(pNode->pRight)) Dim As Byte bBalance = GetBalance(pNode) If bBalance > 1 andalso nKey < pNode->pLeft->nKey Then Return RightRotate(pNode) If bBalance < -1 andalso nKey > pNode->pRight->nKey Then Return LeftRotate(pNode) If bBalance > 1 andalso nKey > pNode->pLeft->nKey Then pNode->pLeft = LeftRotate(pNode->pLeft) Return RightRotate(pNode) Endif If bBalance < -1 andalso nKey < pNode->pRight->nKey Then pNode->pRight = RightRotate(pNode->pRight) Return LeftRotate(pNode) Endif #ENDIF Return pNode End Function Function Tmap##ctkey##ctdata.GetMinNode(pNode As Node##ctkey##ctdata Ptr) As Node##ctkey##ctdata Ptr Dim As Node##ctkey##ctdata Ptr pTemp = pNode While pTemp->pLeft <> 0 pTemp = pTemp->pLeft Wend Return pTemp End Function Function Tmap##ctkey##ctdata.DelNode(pRoot As Node##ctkey##ctdata Ptr, nKey As container_type_key##ctkey) As Node##ctkey##ctdata Ptr If pRoot = 0 Then Return 0 #IF ctkey = String If nKey < *(pRoot->nKey) Then pRoot->pLeft = delNode(pRoot->pLeft, nKey) Elseif nKey > *(pRoot->nKey) Then pRoot->pRight = delNode(pRoot->pRight, nKey) Else If pRoot->pLeft = 0 orelse pRoot->pRight = 0 Then Dim As Node##ctkey##ctdata Ptr pTemp = Iif(pRoot->pLeft <> 0 , pRoot->pLeft , pRoot->pRight) If pTemp = 0 Then If bFlagDelete = 0 Then Deallocate(pRoot->nKey) #IF ctdata = String Deallocate(pRoot->nData) #ENDIF Endif pTemp = pRoot pRoot = 0 Else If bFlagDelete = 0 Then Deallocate(pRoot->nKey) #IF ctdata = String Deallocate(pRoot->nData) #ENDIF Endif *pRoot = *pTemp Endif Delete pTemp Else Dim As Node##ctkey##ctdata Ptr pTemp = GetMinNode(pRoot->pRight) Deallocate(pRoot->nKey) #IF ctdata = String Deallocate(pRoot->nData) #ENDIF pRoot->nKey = pTemp->nKey bFlagDelete = 1 pRoot->nData = pTemp->nData pRoot->pRight = delNode(pRoot->pRight, *(pTemp->nKey)) Endif Endif #ELSE If nKey < pRoot->nKey Then pRoot->pLeft = delNode(pRoot->pLeft, nKey) Elseif nKey > pRoot->nKey Then pRoot->pRight = delNode(pRoot->pRight, nKey) Else If pRoot->pLeft = 0 orelse pRoot->pRight = 0 Then Dim As Node##ctkey##ctdata Ptr pTemp = Iif(pRoot->pLeft <> 0 , pRoot->pLeft , pRoot->pRight) If pTemp = 0 Then #IF ctdata = String If bFlagDelete = 0 Then Deallocate(pRoot->nData) Endif #ENDIF pTemp = pRoot pRoot = 0 Else #IF ctdata = String If bFlagDelete = 0 Then Deallocate(pRoot->nData) Endif #ENDIF *pRoot = *pTemp Endif Delete pTemp Else Dim As Node##ctkey##ctdata Ptr pTemp = GetMinNode(pRoot->pRight) #IF ctdata = String Deallocate(pRoot->nData) #ENDIF pRoot->nKey = pTemp->nKey bFlagDelete = 1 pRoot->nData = pTemp->nData pRoot->pRight = delNode(pRoot->pRight, pTemp->nKey) Endif Endif #ENDIF If pRoot = 0 Then Return pRoot pRoot->bHeight = 1 + Max(GetTreeHeight(pRoot->pLeft), GetTreeHeight(pRoot->pRight)) Dim As Byte bBalance = GetBalance(pRoot) If bBalance > 1 andalso GetBalance(pRoot->pLeft) >= 0 Then Return RightRotate(pRoot) If bBalance > 1 andalso GetBalance(pRoot->pLeft) < 0 Then pRoot->pLeft = LeftRotate(pRoot->pLeft) Return RightRotate(pRoot) Endif If bBalance < -1 andalso GetBalance(pRoot->pRight) <= 0 Then Return LeftRotate(pRoot) If bBalance < -1 andalso GetBalance(pRoot->pRight) > 0 Then pRoot->pRight = RightRotate(pRoot->pRight) Return LeftRotate(pRoot) Endif Return pRoot End Function #IF ctdata = String Type map__return__find__##ctkey##ctdata As Zstring Ptr #ELSE Type map__return__find__##ctkey##ctdata As container_type_data##ctdata #ENDIF #IF ctkey = String Function Tmap##ctkey##ctdata.FindNode(pNode As Node##ctkey##ctdata Ptr , nKey As container_type_key##ctkey) As map__return__find__##ctkey##ctdata If pNode = 0 Then Return 0 Else If nKey < *(pNode->nKey) Then Return FindNode(pNode->pLeft , nKey) Else If nKey > *(pNode->nKey) Then Return FindNode(pNode->pRight , nKey) Else Return pNode->nData Endif Endif Endif End Function #ELSE Function Tmap##ctkey##ctdata.FindNode(pNode As Node##ctkey##ctdata Ptr , nKey As container_type_key##ctkey) As map__return__find__##ctkey##ctdata If pNode = 0 Then Return 0 Else If nKey < pNode->nKey Then Return FindNode(pNode->pLeft , nKey) Else If nKey > pNode->nKey Then Return FindNode(pNode->pRight , nKey) Else Return pNode->nData Endif Endif Endif End Function #ENDIF Sub Tmap##ctkey##ctdata.DelTree(pRoot As Node##ctkey##ctdata Ptr) If pRoot <> 0 Then DelTree(pRoot->pLeft) DelTree(pRoot->pRight) #IF ctkey = String Deallocate(pRoot->nKey) #ENDIF #IF ctdata = String Deallocate(pRoot->nData) #ENDIF Delete (pRoot) Endif End Sub Sub Tmap##ctkey##ctdata.Insert(nKey As container_type_key##ctkey , nData As container_type_data##ctdata) pRoot = InsertNode(pRoot, nKey , nData) End Sub Sub Tmap##ctkey##ctdata.DeleteNode(nKey As container_type_key##ctkey) bFlagDelete = 0 pRoot = DelNode(pRoot, nKey) End Sub Function Tmap##ctkey##ctdata.Find(nKey As container_type_key##ctkey) As container_type_data##ctdata #IF ctdata = String Dim As Zstring Ptr pszTemp = FindNode(pRoot , nKey) If pszTemp Then Return *pszTemp #ELSE Return FindNode(pRoot , nKey) #ENDIF End Function Sub Tmap##ctkey##ctdata.DeleteTree() DelTree(pRoot) End Sub Sub InOrder Overload(pRoot As Node##ctkey##ctdata Ptr) If pRoot <> 0 Then inOrder(pRoot->pLeft) #IF ctkey = String #IF ctdata = String Print *(pRoot->nKey) ; " " ; *(pRoot->nData) #ELSE Print *(pRoot->nKey) ; " " ; pRoot->nData #ENDIF #ELSE #IF ctdata = String Print pRoot->nKey ; " " ; *(pRoot->nData) #ELSE Print pRoot->nKey ; " " ; pRoot->nData #ENDIF #ENDIF inOrder(pRoot->pRight) Endif End Sub Sub printTreePseudographic Overload(pRoot As Node##ctkey##ctdata Ptr , k As Uinteger = 0) If pRoot <> 0 Then printTreePseudographic(pRoot->pRight , k+3) For i As Integer = 0 To k-1 ? " " ; Next #IF ctkey = String ? *(pRoot->nKey) #ELSE ? pRoot->nKey #ENDIF printTreePseudographic(pRoot->pLeft , k+3) Endif End Sub #ENDIF #EndMacro #MACRO MapCreate (mapNamePtr , MapKey , MapData , MapReplaceDataFlag...) map_type (MapKey , MapData , MapReplaceDataFlag) Dim mapNamePtr As Tmap##MapKey##MapData Ptr = New Tmap##MapKey##MapData #EndMacro '''''''''''''''''''Пример''''''''''''''''''''''''' ? "Create MAP (string,string)" MapCreate(map_ss , String , String) For i As Long = 1 To 7 map_ss->insert(Str(i) , Str(i*100)) Next ? "height tree= "; map_ss->GetTreeHeight(map_ss->pRoot); Chr(10) ? "-----Print all tree" ? "key ";"data" InOrder(map_ss->pRoot) ? Chr(10);"Press Any key" Sleep Cls ? Chr(10);"-----Print the tree in the printTreePseudographic view:" printTreePseudographic(map_ss->pRoot) ? Chr(10); "Value from 5 Key = " ; map_ss->Find("5") map_ss->DeleteTree() ? Chr(10);"Press Any key" Sleep() Cls ? "Create MAP (integer,integer)" MapCreate(map_ii , Integer , Integer , 0) For i As Long = 25 To 35 map_ii->insert(i , i*100) Next ? "-----Print all tree" ? "key ";"data" InOrder(map_ii->pRoot) ? Chr(10);"Press Any key" Sleep Cls ? Chr(10);"-----Print the tree in the printTreePseudographic view:" printTreePseudographic(map_ii->pRoot) map_ii->DeleteTree() ? Chr(10);"Press Any key" Sleep