データ構造を確認する過程で個人が遭遇した問題のいくつかを記録します
検索
バランスの取れたバイナリツリー
#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 << "";
}
書いているとき、最初はポインタ操作について少し混乱していました。両方のポインタがツリーのノードを指している場合、ルートポインタが指すツリーを反映するようにポインタを変更できると思いました(再帰なしで使用できるのは他のポインタだけです)。現在の位置を保存するために)、実際には、このアプローチは間違っています。この変更は、渡されたポインターに対してのみ有用であり、ツリー上のポインターは元のノードを指しているため、ツリーは完全に間違っています。
R R *p|
*p |/ \ *p|/ \ C R
A B C B / \ / \
/ => 希望 / \ => 实际 E A B
C E A
/
E
したがって、ノードを回転させるときに渡されるポインターは、補助ポインターではなく、ツリー上のポインターである必要があります。
ソート
序文
並べ替えを確認したところ、前回の調査ではいくつかの方法を理解していなかったので、ヒープの並べ替えにはチェーン構造が使えると思っていたのですが、確認したところ、ツリー構造の逆レベル検索が非常に難しいようで、ついに確認しました。元のヒープソートはチェーン構造に非常に不向きであり、(n ^ 2)に縮退します。ほとんどの並べ替えは、シーケンスにランダムにアクセスできる場合の効果的な方法に基づいています。一般的な(nlogn)並べ替えアルゴリズムは[クイック並べ替え]であり、この[マージ]はチェーン構造に実装されているようですが、リンクリストでは通常高速並べ替えを使用しません。あなたはこれを見ることができます。また、リンクリストのデータメモリが十分である場合、最初にマージするか、最初に配列にコピーしてから、より速くソートするか[ Stackoverflow ]比較を行った人もいます。どの記事か思い出せませんが、そのうちの1つは非常に重要です。重要なのは、データが大きい場合、キャッシュのヒット率も影響を与えるため、配列はリンクされたリストよりも明らかな利点があるということです。したがって、一部の高レベル言語のList <T>は配列であり、その並べ替えメソッドList.Sort()は通常、配列の容量と分割点の品質に基づいています(挿入<高速並べ替え<ヒープ並べ替えは選択の順序のみを示します) )。
リンクされたリストの種類をマージする
以下は、C言語で実装されたリンクリストのマージです
- 中間点検索
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; }
- 分割リスト
/** * 将链表以头尾分割,尾传入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); } }
- リンクリストをマージ
///非递减合并 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++; } }
- 使用する
#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; }