复习数据结构过程中个人遇到的一些问题记录一下
查找
平衡二叉树
#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
void Rotate(PNODE &node) {
PNODE temp = node->left;
node->left = temp->right;
temp->right = node;
node = temp;
}
#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;
break;
}
} else {
if (_r->left != nullptr)
_r = _r->left;
else {
_r->left = (PNODE)malloc(sizeof(NODE));
_r = _r->left;
break;
}
}
}
_r->data = data;
_r->balance = 0;
_r->left = _r->right = nullptr;
PUSH(_r);
//更新平衡度 并记录不平衡根
_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 (_p == _o->left) {
_o->balance += 1;
if (last)
RBalance(&_o->left);
else
LRotate(&_o->left);
} else {
_o->balance -= 1;
if (last)
RBalance(&_o->right);
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 (_p == _o->left) {
_o->balance += 1;
if (!last)
LBalance(&_o->left);
else
RRotate(&_o->left);
} else {
_o->balance -= 1;
if (!last)
LBalance(&_o->right);
else
RRotate(&_o->right);
}
}
}
}
//修正之前节点平衡度
if (_o != nullptr) {
for (int i = 1;; i++) {
if (STK[i - 1] == _o)
break; //此节点后的队列中节点次序已经被破坏
if (STK[i] == STK[i - 1]->left) {
STK[i - 1]->balance += 1;
} else {
STK[i - 1]->balance -= 1;
}
}
}
_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++) {
if(i==10){
cout<<endl;}
_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, 13, nullptr);
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】也有人做过比较,哪篇文章记不清了,但是其中提到了一个很关键的点就是数据大的时候缓存命中率也会有影响,这样数组就比链表优势更加明显了。因此一些高级语言中的 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; }