[Computer Basics] Review of Data Structure

Record some of the problems encountered by individuals in the process of reviewing the data structure

Find
Balanced binary tree
#include <iostream>
#include <math.h>
#include <stdlib.h>
#include <windows.h>

using namespace std;

#pragma region Struct
typedef struct TreeNode {
    int balance;
    int data;
    TreeNode *left;
    TreeNode *right;
    TreeNode *parent;
} * PNODE, NODE;

typedef struct Tree {
    TreeNode *root;
    int height;
} TREE;
#pragma endregion

#pragma region Stack
PNODE *STK = nullptr;
int _stop = 0;
void PUSH(PNODE node) {
    STK[_stop++] = node;
}
PNODE POP() {
    return STK[--_stop];
}
PNODE PEEK() {
    return STK[_stop - 1];
}
#pragma endregion

void setpoint(PNODE *node, int lr) {
    if (lr == 1) {
        (*node)->left->balance = -1;
        (*node)->right->balance = 0;
    } else if (lr == -1) {
        (*node)->left->balance = 0;
        (*node)->right->balance = 1;
    } else {
        (*node)->left->balance = 0;
        (*node)->right->balance = 0;
    }
}
//
void LRotate(PNODE *node) {
    PNODE temp = *node;
    (*node) = (*node)->right;
    temp->right = (*node)->left;
    (*node)->left = temp;
    if (temp->balance == 2) {
        temp->balance = 0;
        (*node)->balance = 0;
    }
}
//
void RRotate(PNODE *node) {
    PNODE temp = *node;
    (*node) = (*node)->left;
    temp->left = (*node)->right;
    (*node)->right = temp;
    if (temp->balance == -2) {
        temp->balance = 0;
        (*node)->balance = 0;
    }
}
///LR balance
void LBalance(PNODE *node) {
    PNODE temp = *node;
    PNODE temp2 = (*node)->left;
    int lr = temp2->right->balance;
    LRotate(&((*node)->left));
    RRotate(node);
    (*node)->balance = 0;
    setpoint(node, lr);
}

///RL balance
void RBalance(PNODE *node) {
    PNODE temp = *node;
    PNODE temp2 = (*node)->right;
    int lr = temp2->left->balance;
    RRotate(&((*node)->right));
    LRotate(node);
    (*node)->balance = 0;
    setpoint(node, lr);
}

PNODE InsertNode(int data, PNODE node) { // O(logn)
    if (node == nullptr)
        return nullptr;
    PNODE _r = node, _p = node, _o = node;
    ///true -L false -R
    bool last = true;

    //找节点
    while (_r != nullptr) {
        PUSH(_r);
        if (_r->data <= data) {
            if (_r->data == data) { //节点已存在
                _stop = 0;
                return _o;
            }
            if (_r->right != nullptr) {
                _r = _r->right;
            } else {
                _r->right = (PNODE)malloc(sizeof(NODE));
                _r = _r->right;
                _r->data = data;
                _r->balance = 0;
                _r->left = _r->right = nullptr;
                PUSH(_r);
                // last = false;
                break;
            }
        } else {
            if (_r->left != nullptr)
                _r = _r->left;
            else {
                _r->left = (PNODE)malloc(sizeof(NODE));
                _r = _r->left;
                _r->data = data;
                _r->balance = 0;
                _r->left = _r->right = nullptr;
                PUSH(_r);
                // last = true;
                break;
            }
        }
    }

    //更新平衡度 并记录不平衡根
    _o = _p = nullptr;
    for (int i = 1; i < _stop; i++) {
        if (STK[i - 1]->left == STK[i]) {
            STK[i - 1]->balance -= 1;
            if (STK[i - 1]->balance == -2) {
                _p = STK[i - 1];
                if (i - 2 >= 0) {
                    _o = STK[i - 2];
                }
            }
            if (i > 2 && _p != nullptr && STK[i - 2] == _p) {
                last = true;
            }
        } else {
            STK[i - 1]->balance += 1;
            if (STK[i - 1]->balance == 2) {
                if (i - 2 >= 0){
                    _o = STK[i - 2];
                }
                _p = STK[i - 1];
            }
            if (i > 2 && _p != nullptr && STK[i - 2] == _p) {
                last = false;
            }
        }
    }

    //平衡
    PNODE newr = STK[0];
    if (_p != nullptr) {
        if (_p->balance == 2) {
            if (_o == nullptr) {
                if (last) {
                    newr = _p->right->left; //RL
                    RBalance(&_p);
                } else {
                    newr = _p->right; //RR
                    LRotate(&_p);
                }
            } else {
                if (last) {
                    if (_p == _o->left)
                        RBalance(&_o->left);
                    else
                        RBalance(&_o->right);
                } else {
                    if (_p == _o->left)
                        LRotate(&_o->left);
                    else
                        LRotate(&_o->right);
                }
            }
        } else {
            if (_o == nullptr) { //_p 是树根
                if (!last) {
                    newr = _p->left->right; //LR
                    LBalance(&_p);
                } else {
                    newr = _p->left; //LL
                    RRotate(&_p);
                }
            } else {// _p 不是树根,则找到p的父节点
                if (!last) {
                    if (_p == _o->left)
                        LBalance(&_o->left);
                    else
                        LBalance(&_o->right);
                } else {
                    if (_p == _o->left)
                        RRotate(&_o->left);
                    else
                        RRotate(&_o->right);
                }
            }
        }
    }

    //修正之前节点平衡度
    if (_o != nullptr) {
        for (int i = 1;; i++) {
            if (STK[i] == STK[i - 1]->left) {
                STK[i - 1]->balance += 1;
            } else {
                STK[i - 1]->balance -= 1;
            }
            if (STK[i - 1] == _o)
                break;
        }
    }

    _stop = 0;
    return newr;
}

Tree *GenerateTree(int *dataarr, int size, PNODE root) {
    Tree *tree = (Tree *)malloc(sizeof(Tree));
    int maxleaf = pow(2, ((int)log2(size) + 1));
    STK = (PNODE *)malloc(maxleaf * sizeof(PNODE));
    PNODE _r = root;
    if (root == nullptr) {
        _r = (PNODE)malloc(sizeof(NODE));
        _r->balance = 0;
        _r->data = dataarr[0];
        _r->parent = _r->left = _r->right = nullptr;
    }
    for (size_t i = 1; i < size; i++) {
        _r = InsertNode(dataarr[i], _r);
    }

    tree->root = _r;
    return tree;
}

void FillNode(PNODE p, int left, int right) {
    p->left = (PNODE)malloc(sizeof(NODE));
    p->left->data = left;
    p->left->left = nullptr;
    p->left->right = nullptr;
    p->right = (PNODE)malloc(sizeof(NODE));
    p->right->data = right;
    p->right->left = nullptr;
    p->right->right = nullptr;
}

int main() {
    // FillNode(p->right, 5, 6);
    int array[] = {1, 20, 5, 18, 6, 17, 7, 16, 13, 12, 21, 22, 9};

    Tree *root = GenerateTree(array, 12, nullptr);
    // RRotate(&o->left);

    cout << "";
    // root;
    cout << "";
}

When writing, I was a little confused about pointer operations at first, thinking that when both pointers point to the node of the tree, a pointer can be modified to reflect the tree pointed to by the root pointer (only other pointers can be used without recursion) To save the current position), in fact, this approach is wrong. This modification is only useful for the pointer passed in, and the pointer on the tree still points to the original node, so the tree is completely wrong.

                R                           R                        *p|          
          *p |/   \                    *p|/   \                        C      R
             A     B                     C      B                    /   \  /   \
            /               => 希望     /  \         =>  实际        E      A      B 
           C                          E     A
          /                                       
         E  

Therefore, the pointer passed in when rotating the node must be a pointer on the tree and not an auxiliary pointer.

Sort
Preface

When reviewing the sorting, I found that the understanding of some methods was not enough in the previous study. I used to think that the chain structure can be used for heap sorting. When I reviewed it, I wanted to find that the tree structure reversed level search seemed difficult, and finally checked it. The original heap sort is very unfriendly to the chain structure and will degenerate to (n^2). Most sorting is based on the effective method when the sequence can be accessed randomly. The general (nlogn) sorting algorithm is [ Quick Sort ] and this [ Merge ] seems to be implemented on the chain structure, but generally do not use fast sort on the linked list. You can take a look at this . Also, if the data memory in the linked list is enough, is it merged faster or copied to the array first and then sorted faster [ Stackoverflow ] Some people have made comparisons. I can’t remember which article, but one of them is very important. The point is that when the data is large, the cache hit rate will also have an impact, so that arrays have more obvious advantages over linked lists. Therefore, List<T> in some high-level languages ​​is an array, and its sorting method List.Sort() is generally based on the capacity of the array and the quality of the split point (insert <fast sort< heap sort only indicates the order of selection) ).

Merge sort of linked list

The following is a linked list merging implemented in C language

  • Midpoint search
    PILNode Mid(PILNode h, PILNode t) {
          
          //快慢指针找
      PILNode p1 = h, p2 = h;
      for (; p2 != t && p2->next != t; p1 = p1->next, p2 = p2->next->next) ;
      return p1;
    }
    
  • Split list
    /**
    * 将链表以头尾分割,尾传入null即分割头节点所指链表
    * 链表头也存储数据
    **/
    void LDivide(PILNode start, PILNode end) {
      if (start != nullptr) {
          // if (end == nullptr)
          //     cout << "   <  L : " << start->data << " -   H : " << "end" << ">  " << endl;
          // else
          //     cout << "   <  L : " << start->data << " -   H : " << end->data << ">  " << endl;
    
          PILNode p1, p2;
          p1 = start;
          p2 = Mid(start, end);
          if (p2->next != end) {
              LDivide(p2, end);
              LDivide(p1, p2);
          }
          if (p1 != p2)
              LMerage(p1, p2, end);
      }
    }
    
  • Merge linked list
    
     ///非递减合并 p1->p2-1 与 p2->p3 两个链表
     ///同样使用n个辅助空间
     ///sup需要外部 声明
     void LMerage(PILNode p1, PILNode p2, PILNode p3) {
          
          
           // cout << p1->data << "  " << p2->data << "  " << (p3 == nullptr ? -1 : p3->data) << endl;
    
      PILNode lh = p1;
      int s, k, k1; //用于记录p2位置 域数组长度
      for (int i = 0; lh != p3; lh = lh->next, i++) {
          
          
          //装填
          if (lh == p2)
             k1 = k = i;
          sup[i] = lh->data;
          s = i;
      }
     
     //以下为书上使用的合并方法
      lh = p1;
      size_t i = 0;
      for (; i < k1 && k <= s;) {
          
          
          int c = i;
          if (sup[i] > sup[k]) {
          
          
              c = k;
              k++;
          } else {
          
          
              i++;
          }
          lh->data = sup[c];
          lh = lh->next;
      }
    
      while (i < k1) {
          
          
          lh->data = sup[i];
          lh = lh->next;
          i++;
      }
    
      while (k <= s) {
          
          
          lh->data = sup[k];
          lh = lh->next;
          k++;
        }
      }
    
  • use
     #include <iostream>
     #include <stdlib.h>
    
     using namespace std;
     int sup[20] = {
          
          0};
     int main() {
          
          
      // MerageSort(table, 10);
      PILNode head = (PILNode)malloc(sizeof(ILNode));
      PILNode node = head, p = nullptr;
      for (size_t i = 1; i < 20; i++) {
          
          
          if (p != nullptr)
              node = p;
          node->data = rand() % 100;
          node->next = (PILNode)malloc(sizeof(ILNode));
          p = node->next;
      }
      node->next = nullptr;
      //最后一个节点一定要指空,mingw里默认不是空指针
      cout << " Origin " <<  endl;
      node = head;
      for (; node != nullptr; node = node->next) {
          
          
          cout << node->data << "  ";
      }
      cout <<  endl;
    
      LDivide(head,nullptr);
    
      cout << " End " << endl;
      node = head;
      for (; node != nullptr; node = node->next) {
          
          
          cout << node->data << "  ";
      }
      cout <<  endl;
    
      return 0;
      }
    
    

Guess you like

Origin blog.csdn.net/q886yes/article/details/109165548