📜  为给定的操作设计有效的数据结构

📅  最后修改于: 2021-04-17 10:46:57             🧑  作者: Mango

设计用于以下操作的数据结构。数据结构应足够有效,以根据操作的频率适应操作。

1) findMin() : Returns the minimum item.
   Frequency: Most frequent

2) findMax() : Returns the maximum item.
    Frequency: Most frequent

3) deleteMin() : Delete the minimum item.
    Frequency: Moderate frequent 

4) deleteMax() : Delete the maximum item.
    Frequency: Moderate frequent 

5) Insert() : Inserts an item.
    Frequency: Least frequent

6) Delete() : Deletes an item.
    Frequency: Least frequent. 

一个简单的解决方案是维护一个排序的数组,其中最小的元素在第一个位置,最大的元素在最后。 findMin(),findMAx()和deleteMax()的时间复杂度为O(1)。但是deleteMin(),insert()和delete()的时间复杂度将为O(n)。

我们可以在O(1)时间内执行最频繁的两次操作,而在O(Logn)时间内执行其他操作吗?
这个想法是使用两个二进制堆(一个最大和一个最小的堆)。主要的挑战是,在删除项目时,我们需要同时从min-heap和max-heap中删除。因此,我们需要某种相互的数据结构。在下面的设计中,我们使用了双向链接列表作为相互的数据结构。双链列表包含所有输入项以及相应的最小和最大堆节点的索引。最小堆和最大堆的节点存储双链表的节点地址。最小堆的根节点将最小项的地址存储在双向链表中。同样,最大堆的根目录将最大项的地址存储在双向链表中。以下是操作的详细信息。

1)findMax():我们从Max Heap的根获得最大值节点的地址。因此,这是一个O(1)操作。

1)findMin():我们从Min Heap的根获得最小值节点的地址。因此,这是一个O(1)操作。

3)deleteMin() :我们从Min Heap的根获得最小值节点的地址。我们使用此地址在双向链表中找到该节点。从双向链表中,我们得到Max Heap的节点。我们从所有三个节点中删除节点。我们可以在O(1)时间从双向链表中删除一个节点。最大和最小堆的delete()操作花费O(Logn)时间。

4)deleteMax() :类似于deleteMin()

5)Insert()我们总是在O(1)时间插入链表的开头。在最大和最小堆中插入地址需要O(Logn)时间。因此总体复杂度为O(Logn)

6)Delete()我们首先在链接列表中搜索该项目。在O(n)时间找到该项目后,我们将从链接列表中将其删除。然后使用存储在链接列表中的索引,在O(Logn)时间将其从Min Heap和Max Heaps中删除。因此,此操作的总体复杂度为O(n)。通过使用平衡的二进制搜索树而不是双向链表作为相互的数据结构,可以将Delete操作优化为O(Logn)。平衡二进制搜索的使用不会影响其他操作的时间复杂度,因为它将像双向链表一样充当相互的数据结构。

以下是上述数据结构的C实现。

// C program for efficient data structure
#include 
#include 
#include 
  
// A node of doubly linked list
struct LNode
{
    int data;
    int minHeapIndex;
    int maxHeapIndex;
    struct LNode *next, *prev;
};
  
// Structure for a doubly linked list
struct List
{
    struct LNode *head;
};
  
// Structure for min heap
struct MinHeap
{
    int size;
    int capacity;
    struct LNode* *array;
};
  
// Structure for max heap
struct MaxHeap
{
    int size;
    int capacity;
    struct LNode* *array;
};
  
// The required data structure
struct MyDS
{
    struct MinHeap* minHeap;
    struct MaxHeap* maxHeap;
    struct List* list;
};
  
// Function to swap two integers
void swapData(int* a, int* b)
{ int t = *a;   *a = *b;   *b = t; }
  
// Function to swap two List nodes
void swapLNode(struct LNode** a, struct LNode** b)
{ struct LNode* t = *a; *a = *b; *b = t; }
  
// A utility function to create a new List node
struct LNode* newLNode(int data)
{
    struct LNode* node =
        (struct LNode*) malloc(sizeof(struct LNode));
    node->minHeapIndex = node->maxHeapIndex = -1;
    node->data = data;
    node->prev = node->next = NULL;
    return node;
}
  
// Utility function to create a max heap of given capacity
struct MaxHeap* createMaxHeap(int capacity)
{
    struct MaxHeap* maxHeap =
     (struct MaxHeap*) malloc(sizeof(struct MaxHeap));
    maxHeap->size = 0;
    maxHeap->capacity = capacity;
    maxHeap->array =
     (struct LNode**) malloc(maxHeap->capacity * sizeof(struct LNode*));
    return maxHeap;
}
  
// Utility function to create a min heap of given capacity
struct MinHeap* createMinHeap(int capacity)
{
    struct MinHeap* minHeap =
       (struct MinHeap*) malloc(sizeof(struct MinHeap));
    minHeap->size = 0;
    minHeap->capacity = capacity;
    minHeap->array =
       (struct LNode**) malloc(minHeap->capacity * sizeof(struct LNode*));
    return minHeap;
}
  
// Utility function to create a List
struct List* createList()
{
    struct List* list =
      (struct List*) malloc(sizeof(struct List));
    list->head = NULL;
    return list;
}
  
// Utility function to create the main data structure
// with given capacity
struct MyDS* createMyDS(int capacity)
{
    struct MyDS* myDS =
        (struct MyDS*) malloc(sizeof(struct MyDS));
    myDS->minHeap = createMinHeap(capacity);
    myDS->maxHeap = createMaxHeap(capacity);
    myDS->list = createList();
    return myDS;
}
  
// Some basic operations for heaps and List
int isMaxHeapEmpty(struct MaxHeap* heap)
{  return (heap->size == 0); }
  
int isMinHeapEmpty(struct MinHeap* heap)
{  return heap->size == 0; }
  
int isMaxHeapFull(struct MaxHeap* heap)
{  return heap->size == heap->capacity; }
  
int isMinHeapFull(struct MinHeap* heap)
{  return heap->size == heap->capacity; }
  
int isListEmpty(struct List* list)
{  return !list->head;   }
  
int hasOnlyOneLNode(struct List* list)
{    return !list->head->next && !list->head->prev; }
  
  
// The standard minheapify function.  The only thing it does extra
// is swapping indexes of heaps inside the List
void minHeapify(struct MinHeap* minHeap, int index)
{
    int smallest, left, right;
    smallest = index;
    left = 2 * index + 1;
    right = 2 * index + 2;
  
    if ( minHeap->array[left] &&
         left < minHeap->size &&
         minHeap->array[left]->data < minHeap->array[smallest]->data
       )
        smallest = left;
  
    if ( minHeap->array[right] &&
         right < minHeap->size &&
         minHeap->array[right]->data < minHeap->array[smallest]->data
       )
        smallest = right;
  
    if (smallest != index)
    {
        // First swap indexes inside the List using address
        // of List nodes
        swapData(&(minHeap->array[smallest]->minHeapIndex),
                 &(minHeap->array[index]->minHeapIndex));
  
        // Now swap pointers to List nodes
        swapLNode(&minHeap->array[smallest],
                  &minHeap->array[index]);
  
        // Fix the heap downward
        minHeapify(minHeap, smallest);
    }
}
  
// The standard maxHeapify function.  The only thing it does extra
// is swapping indexes of heaps inside the List
void maxHeapify(struct MaxHeap* maxHeap, int index)
{
    int largest, left, right;
    largest = index;
    left = 2 * index + 1;
    right = 2 * index + 2;
  
    if ( maxHeap->array[left] &&
         left < maxHeap->size &&
         maxHeap->array[left]->data > maxHeap->array[largest]->data
       )
        largest = left;
  
    if ( maxHeap->array[right] &&
         right < maxHeap->size &&
         maxHeap->array[right]->data > maxHeap->array[largest]->data
       )
        largest = right;
  
    if (largest != index)
    {
        // First swap indexes inside the List using address
        // of List nodes
        swapData(&maxHeap->array[largest]->maxHeapIndex,
                 &maxHeap->array[index]->maxHeapIndex);
  
        // Now swap pointers to List nodes
        swapLNode(&maxHeap->array[largest],
                  &maxHeap->array[index]);
  
        // Fix the heap downward
        maxHeapify(maxHeap, largest);
    }
}
  
// Standard function to insert an item in Min Heap
void insertMinHeap(struct MinHeap* minHeap, struct LNode* temp)
{
    if (isMinHeapFull(minHeap))
        return;
  
    ++minHeap->size;
    int i = minHeap->size - 1;
    while (i && temp->data < minHeap->array[(i - 1) / 2]->data )
    {
        minHeap->array[i] = minHeap->array[(i - 1) / 2];
        minHeap->array[i]->minHeapIndex = i;
        i = (i - 1) / 2;
    }
  
    minHeap->array[i] = temp;
    minHeap->array[i]->minHeapIndex = i;
}
  
// Standard function to insert an item in Max Heap
void insertMaxHeap(struct MaxHeap* maxHeap, struct LNode* temp)
{
    if (isMaxHeapFull(maxHeap))
        return;
  
    ++maxHeap->size;
    int i = maxHeap->size - 1;
    while (i && temp->data > maxHeap->array[(i - 1) / 2]->data )
    {
        maxHeap->array[i] = maxHeap->array[(i - 1) / 2];
        maxHeap->array[i]->maxHeapIndex = i;
        i = (i - 1) / 2;
    }
  
    maxHeap->array[i] = temp;
    maxHeap->array[i]->maxHeapIndex = i;
}
  
  
// Function to find minimum value stored in the main data structure
int findMin(struct MyDS* myDS)
{
    if (isMinHeapEmpty(myDS->minHeap))
        return INT_MAX;
  
    return myDS->minHeap->array[0]->data;
}
  
// Function to find maximum value stored in the main data structure
int findMax(struct MyDS* myDS)
{
    if (isMaxHeapEmpty(myDS->maxHeap))
        return INT_MIN;
  
    return myDS->maxHeap->array[0]->data;
}
  
// A utility function to remove an item from linked list
void removeLNode(struct List* list, struct LNode** temp)
{
    if (hasOnlyOneLNode(list))
        list->head = NULL;
  
    else if (!(*temp)->prev) // first node
    {
        list->head = (*temp)->next;
        (*temp)->next->prev = NULL;
    }
    // any other node including last
    else
    {
        (*temp)->prev->next = (*temp)->next;
        // last node
        if ((*temp)->next)
            (*temp)->next->prev = (*temp)->prev;
    }
    free(*temp);
    *temp = NULL;
}
  
// Function to delete maximum value stored in the main data structure
void deleteMax(struct MyDS* myDS)
{
    MinHeap *minHeap = myDS->minHeap;
    MaxHeap *maxHeap = myDS->maxHeap;
  
    if (isMaxHeapEmpty(maxHeap))
        return;
    struct LNode* temp = maxHeap->array[0];
  
    // delete the maximum item from maxHeap
    maxHeap->array[0] =
        maxHeap->array[maxHeap->size - 1];
    --maxHeap->size;
    maxHeap->array[0]->maxHeapIndex = 0;
    maxHeapify(maxHeap, 0);
  
    // remove the item from minHeap
    minHeap->array[temp->minHeapIndex] = minHeap->array[minHeap->size - 1];
    --minHeap->size;
    minHeap->array[temp->minHeapIndex]->minHeapIndex = temp->minHeapIndex;
    minHeapify(minHeap, temp->minHeapIndex);
  
    // remove the node from List
    removeLNode(myDS->list, &temp);
}
  
// Function to delete minimum value stored in the main data structure
void deleteMin(struct MyDS* myDS)
{
    MinHeap *minHeap = myDS->minHeap;
    MaxHeap *maxHeap = myDS->maxHeap;
  
    if (isMinHeapEmpty(minHeap))
        return;
    struct LNode* temp = minHeap->array[0];
  
    // delete the minimum item from minHeap
    minHeap->array[0] = minHeap->array[minHeap->size - 1];
    --minHeap->size;
    minHeap->array[0]->minHeapIndex = 0;
    minHeapify(minHeap, 0);
  
    // remove the item from maxHeap
    maxHeap->array[temp->maxHeapIndex] = maxHeap->array[maxHeap->size - 1];
    --maxHeap->size;
    maxHeap->array[temp->maxHeapIndex]->maxHeapIndex = temp->maxHeapIndex;
    maxHeapify(maxHeap, temp->maxHeapIndex);
  
    // remove the node from List
    removeLNode(myDS->list, &temp);
}
  
// Function to enList an item to List
void insertAtHead(struct List* list, struct LNode* temp)
{
    if (isListEmpty(list))
        list->head = temp;
  
    else
    {
        temp->next = list->head;
        list->head->prev = temp;
        list->head = temp;
    }
}
  
// Function to delete an item from List. The function also
// removes item from min and max heaps
void Delete(struct MyDS* myDS, int item)
{
    MinHeap *minHeap = myDS->minHeap;
    MaxHeap *maxHeap = myDS->maxHeap;
  
    if (isListEmpty(myDS->list))
        return;
  
    // search the node in List
    struct LNode* temp = myDS->list->head;
    while (temp && temp->data != item)
        temp = temp->next;
  
    // if item not found
    if (!temp || temp && temp->data != item)
        return;
  
    // remove item from min heap
    minHeap->array[temp->minHeapIndex] = minHeap->array[minHeap->size - 1];
    --minHeap->size;
    minHeap->array[temp->minHeapIndex]->minHeapIndex = temp->minHeapIndex;
    minHeapify(minHeap, temp->minHeapIndex);
  
    // remove item from max heap
    maxHeap->array[temp->maxHeapIndex] = maxHeap->array[maxHeap->size - 1];
    --maxHeap->size;
    maxHeap->array[temp->maxHeapIndex]->maxHeapIndex = temp->maxHeapIndex;
    maxHeapify(maxHeap, temp->maxHeapIndex);
  
    // remove node from List
    removeLNode(myDS->list, &temp);
}
  
// insert operation for main data structure
void Insert(struct MyDS* myDS, int data)
{
    struct LNode* temp = newLNode(data);
  
    // insert the item in List
    insertAtHead(myDS->list, temp);
  
    // insert the item in min heap
    insertMinHeap(myDS->minHeap, temp);
  
    // insert the item in max heap
    insertMaxHeap(myDS->maxHeap, temp);
}
  
// Driver program to test above functions
int main()
{
    struct MyDS *myDS = createMyDS(10);
    // Test Case #1
    /*Insert(myDS, 10);
    Insert(myDS, 2);
    Insert(myDS, 32);
    Insert(myDS, 40);
    Insert(myDS, 5);*/
  
    // Test Case #2
    Insert(myDS, 10);
    Insert(myDS, 20);
    Insert(myDS, 30);
    Insert(myDS, 40);
    Insert(myDS, 50);
  
    printf("Maximum = %d \n", findMax(myDS));
    printf("Minimum = %d \n\n", findMin(myDS));
  
    deleteMax(myDS);  // 50 is deleted
    printf("After deleteMax()\n");
    printf("Maximum = %d \n", findMax(myDS));
    printf("Minimum = %d \n\n", findMin(myDS));
  
    deleteMin(myDS); // 10 is deleted
    printf("After deleteMin()\n");
    printf("Maximum = %d \n", findMax(myDS));
    printf("Minimum = %d \n\n", findMin(myDS));
  
    Delete(myDS, 40); // 40 is deleted
    printf("After Delete()\n");
    printf("Maximum = %d \n", findMax(myDS));
    printf("Minimum = %d \n", findMin(myDS));
  
    return 0;
}

输出:

Maximum = 50
Minimum = 10

After deleteMax()
Maximum = 40
Minimum = 10

After deleteMin()
Maximum = 40
Minimum = 20

After Delete()
Maximum = 30
Minimum = 20