记录自己下半年写题目的记录。题目来自书或者网站。
练习(一)的地址:
https://blog.csdn.net/qq_41358574/article/details/117098620?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522162343250816780357289113%2522%252C%2522scm%2522%253A%252220140713.130102334.pc%255Fblog.%2522%257D&request_id=162343250816780357289113&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2blogfirst_rank_v2~rank_v29-2-117098620.nonecase&utm_term=%E5%88%B7%E9%A2%98&spm=1018.2226.3001.4450

文章目录

  • 知识点整理
  • 1.一棵二叉排序树,设计算法查找两个结点之和等于给定值x的结点
  • 2.树的层次遍历
  • 3.一二叉排序树中的关键字由整数构成,为了查找某关键字k,会得到一个查找序列,判断一个数组a中的序列是否为该二叉排序的查找序列
  • 4.求关键字分别为x,y的结点的最近公共祖先
  • 5.设计算法将二叉排序树变为有序链表,要求不能创建新结点,只修改指针
  • 6.设计算法交换二叉树b的所有左右子树要求空间复杂度为1
  • 7.设计算法交换二叉树b的所有左右子树要求不破坏原二叉树结构
  • 8.设计算法利用结点的右孩子指针将一棵二叉树的叶结点从左往右串成单链表
  • 9.设计算法输出所有根结点到叶结点的路径及其路径和
  • 10.【面试题9-11★★★】一个含有13个元素的数组为前半部分、后半部分是递增有序,但整个数组不是递增数组,且不知道前、后两个部分中的元素个数,怎么最快地找出其中的一个数
  • 11.一个非降序数组,若target在数组中出现,返回位置,否则返回它将插入的位置
  • 12.二分插入排序
  • 13.希尔排序
  • 14.桶排序实战:用链表表示桶,从文件中读取数字
  • 15.一个序列用带头结点的单链表存储,采用快速排序求递增排序
  • 16.二叉查找树的操作
    • 遍历操作:
    • 插入结点
    • 二叉查找树的删除操作
    • 二叉查找树的查找操作
    • 判断一个数组是否是二叉查找树的后序遍历
  • 17.线索二叉树
    • 数据结构如下:
    • 寻找中序遍历线索二叉树的前驱和后继结点
    • 先序、后序遍历的前驱后继
    • 线索二叉树中插入结点
    • . 二叉树的线索化算法实现
    • 遍历线索二叉树
  • 18.分块查找

知识点整理

  • 平衡二叉树插入结点时速度比较慢
  • 平衡二叉树的各项操作的时间复杂度为o(logn)
  • 有序数组的查找性能高但删除性能低,有序链表的查找性能低但删除性能高,AVL和哈希表的查找和删除性能都高

1.一棵二叉排序树,设计算法查找两个结点之和等于给定值x的结点

1.思路一 中序遍历产生中序序列(左子树所有结点的关键字均小于根节点关键字)

typedef struct node {char data;struct node* lchild;struct node* rchild;
}btnode;
void InOrder(btnode* bt, vector<btnode*>& order) {//order:中序遍历产生的序列InOrder(bt->lchild, order);order.push_back(bt);InOrder(bt->rchild, order);
}
bool FindSum(vector<btnode*>order, int x, btnode* &p1, btnode* &p2)//p1 p2传入的是引用 这样能得到和为x的结点
{//查找两个结点值之和等于x的p1和p2int i = 0, j = order.size()-1;while (i < j){if (order[i]->data + order[j]->data == x) {p1 = order[i];p2 = order[j];return true;}else if (order[i]->data + order[j]->data > x){j--;}elsei++;}return false;
}bool TwoNodeSum(btnode* bt, int x, btnode*& p1, btnode*& p2)
{vector<btnode*>order;InOrder(bt, order);if (FindSum(order,x, p1, p2)) return true;else return false;
}

思路二 采用两个栈分别记录bt的左下结点和右下结点(初始状态保存根结点的左下结点和右下结点)

bool TwoNodeSum(btnode* bt, int x, btnode*& p1, btnode*& p2)
{stack<btnode*>left, right;btnode* p = bt, * q;while (p != NULL) {if (p->lchild != nullptr) {left.push(p->lchild); p = p->lchild;}p = bt;//注意这个步骤 此后根结点再次赋给pif (p->rchild != nullptr) {right.push(bt->rchild);p = p->rchild;}while (!left.empty() && !right.empty()){p1 = left.top();p2 = right.top();if (p1->data + p2->data > x)//找次大结点 即p2左孩子的所有右下结点进栈{q = p2;right.pop();if (q->lchild != NULL){p = q->lchild;while (p) {right.push(p);p = p->rchild;}}}else if (p1->data + p2->data < x){//找次小结点q = p1;left.pop();if (q->rchild != NULL){p = q->rchild;while (p){left.push(p);p = p->lchild;}}}else return true;}};return false;
}

2.树的层次遍历

按从上到下从左到右的顺序输出各个结点的值,如果从根到某个叶节点的路径上有的结点没有在输入中给出,或者给出超过一次,应该输出-1
样例输入:
(11, LL) (7, LLL) (8, R) (5, ) (4, L) (13, RL) (2, LLR) (1, RRR) (4, RR) ()
输出:
5 4 8 11 13 4 7 2 1


#include<queue>
struct Node {int val;bool ifHas;//是否被赋值过Node* left, * right;Node() :ifHas(false), left(NULL), right(NULL) {};
};
Node* root;
char s[maxn];//保存读入结点
void addNode(int v, char* s) {int n = strlen(s);for (int i = 0; i < n; i++){if (s[i] == 'L') {if (root->left == NULL){root->left = new Node();//结点不存在,建立新节点root = root->left;}}else  if (s[i] == 'R') {if (root->right == NULL){root->right = new Node();root = root->right;}}if (root->ifHas == true) continue;root->val = v;//赋值root->ifHas = true;//置为已经访问}
}//插入结点的操作
bool bfs(vector<int>& ans)
{Node* temp;queue<Node*>q;q.push(root);while (!q.empty()){temp = q.front();if (temp->ifHas == false) return false;//注意这个验错。如果没有被赋值过,表明输入有误ans.push_back(q.front()->val);q.pop();if (temp->left)q.push(temp->left);if (temp->right)q.push(temp->right);return true;}
}
bool read_input()
{Node node;int val;while (1){if (scanf("%s", s) != 1) return false;if (!strcmp("()", s)) break;//读到结尾标志,退出循环sscanf(&s[1],"%d",&val);//s[1]是字符 &s[1]是字符串“11,LL)”addNode(val, strchr(s, ',') + 1);}return true;
}

3.一二叉排序树中的关键字由整数构成,为了查找某关键字k,会得到一个查找序列,判断一个数组a中的序列是否为该二叉排序的查找序列

//假设序列a有n个关键字,如果查找成功则a[n-1]=k,用i扫描a数组,p用于在二叉树bt中查找(p的初值指向根节点) 注意:没查找一层都比较p->key与a[i]是否相等
//如果不相等 返回false
bool FindSer(Node* bt, int k, int a[], int n)
{if (bt == NULL) return false;if (a[n - 1] != k) return false;//先提前判断这个Node* p = bt;int i = 0;while (i < n && p != NULL){if (p->val != a[i]) return false;if (k > p->val) p = p->right;else if (k < p->val) p = p->right;i++;}if (p != NULL) return true;return false;
}

4.求关键字分别为x,y的结点的最近公共祖先


Node* LCA(Node*bt,int x,int y)
{{if (bt == nullptr) return NULL;if (x < bt->left->val && y < bt->left->val) return LCA(bt->left, x, y);else if (x > bt->right->val && y > bt->right->val) return LCA(bt->right, x, y);else return bt;//注意 如果以上两种情况都不是,则bt为最近公共结点}

5.设计算法将二叉排序树变为有序链表,要求不能创建新结点,只修改指针

方法一:

//1.递归的方法 将二叉树bt中所有结点的左指针lchild转化为指向前驱结点,右指针转化为指向后继结点
//if bt->lchild==null first = bt,if bt->rchild==null last =bt
//注意需要销毁双链表
void convert(Node* bt, Node*& first, Node*& last)
{if (bt == nullptr) {//空树first = nullptr;last = nullptr;}Node* lfirst, * llast, * rfirst, * rlast;//递归调用时左子树和右子树的首位指针,一共四个if (bt->left == nullptr) first = bt;else if (bt->left != nullptr) {convert(bt->left, lfirst, llast);first = lfirst;bt->left = llast;llast->right = bt;}if (bt->right == nullptr)last = bt;else {convert(bt->right, rfirst, rlast);last = rlast;bt->right = rfirst;rfirst->left = bt;}
}
void Display(Node* first, Node* last)
{if (first != NULL) {//输出转化后的双链表while (first != last){cout << first->val << ",";first = first->right;}cout << first->val;//最后一个结点的值}}
void destroy(Node*& L)
{//销毁双链表Node* pre = L, *p = pre->right;//一个首结点 一个首结点的后继结点while (pre->right){free(pre);pre = p;p = pre->right;}free(pre);//注意最后还有一个结点要释放
}

方法二:
中序遍历 用pre全局变量指向中序遍历当前访问结点bt的前驱节点,初始为NULL,中序访问bt时,设置pre->rchild=bt bt->lchid = pre
两个方法的输出和销毁双链表函数是一样的

Node* pre = NULL;
void InOrder(Node* bt)
{if (bt == NULL) return;if (bt->left) {InOrder(bt->left);bt->left = pre;pre->right = bt;}if (pre != NULL)pre->right = bt;bt->left = pre;pre = bt;InOrder(bt->right);//递归构造右子树
}
void convert(Node* bt, Node*& first)
{//转化为首结点为first的双链表Node* p = bt;if (p->left != NULL){p = p->left;}first = p;pre = NULL;InOrder(bt);}
int main() {Node* first,*bt;//用排序二叉树算法建树convert(bt, first);//转化为有序单链表//输出双链表的函数//销毁双链表}

6.设计算法交换二叉树b的所有左右子树要求空间复杂度为1

void swap(btnode*b)
{btnode*temp;
if(b!=NULL)
{swap(b->lchild);
swap(b->rchild);
temp=b->lchild;
b->lchild=b->rchild;
b->rchild=temp;
}
}
//基于后序遍历算法

7.设计算法交换二叉树b的所有左右子树要求不破坏原二叉树结构

btnode* swap(btnode*b)
{btnode*t,*t1,*t2;
if(b==NULL)t=NULL;
else
{t=(btnode*)malloc(sizof(btnode));//复制根节点
t->data=b->data;
t1=swap(b->lchild);
t2=swap(b->rchild);
t->lchild=t2;
t->rchild=t1;
}
return t;
}

8.设计算法利用结点的右孩子指针将一棵二叉树的叶结点从左往右串成单链表

//先序遍历的方法,尾插法构建叶结点,head指向建立单链表的首结点,tail指向尾结点
//head tail以引用的方式传入
void link(btnode*b,btnode*&head,btnode*&tail)
{if(b!=NULL)
{if(b->lchild==NULL&&b->rchild==NULL)//叶结点
{if(head==NULL){//此时为第一个叶结点
head=b;
tail=head;
}
else
{tail->rchild=b;
tail=b;
}
}
if(b->lchild!=NULL){link(b->lchild,head,tail);
}
if(b->rchild!=NULL)link(b->rchild,head,tail);
}
//创建并输出叶结点构成的单链表
void vreateLink(btnode*b)
{btnode*head=NULL,*tail;
link(b,head,tail)//注意head一开始指向null
tail->rchild=NULL;//注意尾结点的rchild置空
btnode*p=head;
while(p!=NULL)
{cout<<p->data<<",";
p=p->next;
}}

9.设计算法输出所有根结点到叶结点的路径及其路径和

void dispapath(vector<int>path)
{vector<int>::iterator it;
int sum=0;
for(it=path.begin();it!=path.end();it++)
{sum+=*it;
cout<<*it<<" ";
}
cout<<sum;void pathSum(btnode*b,vector<int>path)
{if(b==NULL)return;
path.push_back(b->data);
if(b->lchild==NULL&&b->rchild==NULL)
{dispath(path);//找到一个叶结点,输出一条路径
}
pathSum(b->lchild,path);
pathSum(b->rchild,path);//如果不是叶结点,先序遍历的方式继续寻找后面的结点

10.【面试题9-11★★★】一个含有13个元素的数组为前半部分、后半部分是递增有序,但整个数组不是递增数组,且不知道前、后两个部分中的元素个数,怎么最快地找出其中的一个数

如[2,4,5,6,7,8][1,3,5,6,7]
解:由于不知道前、后两个有序部分中的元素个数,所以先要将其找出来。假设前、后两个部分分别为a[0.m]和a[m+.n-1],先采用顺序方法在a[0…m]中从前向后查找,若a[i]==target(目标元素),找到后算法结束,或者发现元素逆序后退出循环(即找到分界线
元素a[m]),然后在a[m+1.n-1]有序区间中采用二分查找
上述过程对应的时间复杂度为O(n)。对应的算法如下:

int binSearch(int a[],int low,int high,int target)
{//二分查找的函数
while(low<=high)
{int mid=low+(high-low)>>1;//位运算更高效
if(a[mid]==target) return mid;
else if(a[mid]>target)
high=mid-1;
else
low=mid+1;
}
return -1;//没找到
}
int search(int a[],int n,int target)
{int i;
for(i = 0;i < n;i++)
{if(a[i]==target)return i;
if(a[i]>a[i+1])break;
}
int low=i+1,high=n-1;
binSearch(a,low,high,target);//如果a[0,..m]中没有找到目标,则在第二个递增数组中查找

11.一个非降序数组,若target在数组中出现,返回位置,否则返回它将插入的位置

写法1:

int SearchInsert(int a[],int n,int target)
{if(a[n-1] < target) return n;//a是一递增数组int low=0,high = n-1;while(low <= high){int mid = (low+high)/2;if(a[mid] > target) high=mid-1;else if(a[mid] < target) low=mid+1;else return mid;}return low;
}

写法2:

int SearchInsert(int a[],int n,int target)
{if(a[n-1] < target) return n;//a是一递增数组int low=0,high = n-1;while(low < high){int mid = (low+high)/2;if(a[mid] > target) high=mid;else  low=mid+1;}return high;
}

12.二分插入排序

void BinInsertSort(int a[],int n)
{int i,j,low,high,mid;int tmp;for(i = 1;i < n;i++){if(a[i] < a[i-1]){tmp = a[i];low=0;high=i-1;while(low<=high){mid = (low+high)/2;if(a[mid] > tmp) high=mid-1;else low=mid+1;}for(j=i-1;j>=high+1;j--)a[j+1]=a[j];//集中进行元素后移a[high+1]=tmp;}}
}int main() {int a[5]={1,74,3,15,6};
BinInsertSort(a,5);
for(int i = 0;i < 5;i++)
cout<<a[i]<<" ";}

13.希尔排序

void shell(int a[],int n)
{int i,j,d;int tmp;d = n/2;while(d > 0){for(i = d;i < n;i++)
{ j = i - d;
tmp = a[i];
while(j>=0 && a[j] > tmp)
{a[j+d] = a[j];j = j-d;
}
a[j+d] = tmp;}d = d/2;}
}

是不稳定的排序算法。
每一趟不一定产生有序区,最后一趟产生全部的有序序列。

直接插入排序:每一趟产生的有序区不一定是全局有序的。是稳定的排序算法。平均时间复杂度为o(n²)
对于直接插入排序,初始数据越接近正序性能越好。

14.桶排序实战:用链表表示桶,从文件中读取数字

15.一个序列用带头结点的单链表存储,采用快速排序求递增排序

先找划分基准,再分成两半递归排序

void swap(int&x,int &y)
{int temp = x;
x = y;
y = temp;
}
LinkNode* Paration(LinkNode* first,LinkNode*tail)
{if(first == tail) return first;//只有一个结点
LinkNode* pt = first,* p =pt->next;
int temp = first->data;//基准值
while(true)
{if(p->data < temp)
{pt = pt->next;
swap(pt->data,p->data);//如果p结点小于temp
}
if(p == tail) break;
p = p->next;
}
swap(pt->data,first->data);//找到划分位置,即pt指向的结点
return pt;
}
void QuickSort(LinkNode*&first,LinkNode*&tail)
{if(first!=NULL && tail != NULL && first != tail)
{LinkNode*pt = Paration(first,tail);
QuickSort(first,pt);
QuickSort(pt->next,tail);
}
}

通过修改结点的值实现,没有改变结点地址。

16.二叉查找树的操作

遍历操作:

void inSort(btnode*node)
{if(node!=NULL)
{inSort(node->lchild);//递归遍历左子树
std::cout<<node->data<<std::endl;//输出结点数据
inSort(node->rchild);//递归遍历右子树
}
}

插入结点

步骤:如果二叉查找树为空,则插入结点就为根节点
否则将待插入结点与根节点进行比较,如果小于根节点就插入到左子树,大于根节点就插入到右子树中

void insert(btnode*node)
{btnode*temp = NULL,*cnt;//中间指针
cnt = root;
while(cnt != NULL)
{temp=cnt;//用于保存最后一个有效结点
if(cnt->data > node->data)
{cnt = cnt->lchild;
}
else
{cnt = cnt->rchild;
}
}
if(temp==NULL)
//根节点为空
{root = node;
count++;}
if(node->data<temp->data)
{temp->lchild = node;
count++;}
else
{temp->rchild = node;
count++;}
}

二叉查找树的删除操作

考虑几种情况:
如果没有子女结点,则修改父节点的指针,使其指向NULL,删除结点x
如果结点x只有一个孩子结点,修改其父节点和孩子结点的parent指针 建立联系,如果左右孩子都存在 用左子树中的最大值或者右子树的最小值代替x

二叉查找树的查找操作

btnode search(DataType k)
{btnode*node = root;
while(node!=NULL)
{if(node->data>k)
node= node->lchild;
else if(node->data < k)
node = node->rchild;
else
break;//相等则退出
}
return node;
}

判断一个数组是否是二叉查找树的后序遍历

//判断一个数组是否是一个二叉查找树的后序遍历
bool postSequence(int sequence[],int len)
{if(sequence == NULL || len <= 0) return false;//先验错
int root = sequence[len-1];//找到根节点
int i = 0;
for(;i<len-1;i++)
if(sequence[i]>root) break;//左子树均小于根节点 这里i是下标也是长度
int j = i;
for(;j < len-1;j++)//注意这里j是下标而不是长度
if(sequence[j] < root) return false;//如果右子树有小于根节点的 返回false
bool left = true;//判断左子树是否是查找树
if(i > 0)
{//有可能没有左子树,故加上i>0的判断left = postSequence(sequence,i);//i是左子树的长度
}
bool right = true;
if(j < len-1)
right = postSequence(sequence+i,len-i-1);//注意右子树开始的序列和右子树的长度
return (right && left);
}int main()
{int s[7];for(int i = 0;i <7;i++)cin>>s[i];bool res=postSequence(s,7);if(res)cout<<"是";
}

5 7 6 9 11 10 8

17.线索二叉树

我们利用二叉树链式存储结构的空指针来存储结点的直接前驱指针和直接后继结点指针,这些指针称为线索,利用线索来保留前驱和后继结点信息的二叉树称为线索二叉树。
我们设定结点左指针指向前驱节点,右指针指向后继结点,且每个结点增加两个标志量lFlag和rFlag,当lchild rchild是指向孩子节点的指针时相应的标志量为1,是线索时为0
也就是说rchild lchild可能时指向孩子的指针也可能是线索

数据结构如下:

template<typename DataType>class ThreadBTNode{public:
friend class ThreadBT<DataType>;
ThreadBTNode(DataType data)
{lFlag = rFlag =0;
this->data = data;
lchild = rchild = NULL;
}
ThreadBTNode()
{lFlag = rFlag =0;
lchild = rchild = NULL;//带数据结点的构造函数和空构造函数
}
private:
ThreadBTNode<DataType>*lchild,*rchild;//左右指针域
int lFlag,rFlag;//标志量
DataType data;//数据域
};
template<typename DataType>class ThreadBT{public:
ThreadBT(){root = NULL;
}
ThreadBT(DataType data)
{root = new ThreadBTNode< DataType>(data);
}
private:}

寻找中序遍历线索二叉树的前驱和后继结点

线索二叉树的前驱和后继结点与使用的遍历方式有关,线索二叉树之间的区别就是根据不同的遍历方式其结点的前驱和后继不同
对二叉树进行一次中序遍历便明白结点node的前驱节点是左子树中最右边的结点,后继结点是右子树最左边的结点

template<typename DataType>ThreadBTNode<DataType>*ThreadBT<DataType>::prior(ThreadBTNode<DataType>*node)
{ThreadBTNode<DataType>*s = node->lchild;
if(node->lFlag==1)
{//为1时代表node的左指针不是线索,不指向前驱,如果lFlag为0,可以直接返回s
while(s->Flag==1)
{s = s->rchild;
}//一直找结点的右子结点,直到找到左子树的最右子节点}
return s;//返回前驱
}

同理查找后继:

template<typename DataType>ThreadBTNode<DataType>*ThreadBT<DataType>::succ(ThreadBTNode<DataType>*node)
{ThreadBTNode<DataType>*s;
s = node->rchild;
if(node->rFlag == 1)
{while(s->lFlag == 1)//循环查找结点的右子节点,找到右子树的最左节点
s = s->lchild;
}
return s;
}

先序、后序遍历的前驱后继

标志ltag和rtag,并约定:
0 结点中的 lchild字段指向左孩子;
ltag=
1 结点中的 lchild字段指向前驱;
0 结点中的 rchild字段指向右孩子;
rtag=
1 结点中的 rchild字段指向后继;

typedef    struct   tbnode{elementtype    data;tbnode   *lchild,  *rchild;int   ltag,  rtag;}tbnode

(1) 先序线索二叉树中先序后继的求解——先序后继
对先序线索二叉树中任意结点P,求其先序后继。
讨论:
(a) 若p有左孩子 ——按照遍历的过程描述(PPLPR)可知,
其后继应为:左子树PL中的第一个结点,
p的左孩子结点,
因此, p->lchild为其后继;
(b) 否则,*p有右孩子 ——类似地,可知
p->rchild为其后继;
© 否则,
p->rchild为其后继线索;
由此得算法如下:

tbnode   *presuc(tbnode *p) {if ( p -> ltag == 0 ) return ( p -> lchild );else return ( p -> rchild );
}

后序前驱的求解
分析:
(a) 若p有右孩子 —— 右孩子结点是其前驱;
(b) 否则,若
P有左孩子 —— 左孩子结点是其前驱;
© 否则 —— p -> lchild是其前驱线索 。
与先序后继的求解方式对称。
由此得算法如下:

   tbnode   *postpre(tbnode *p) {if ( p -> rtag == 0 ) return ( p -> rchild );else return ( p -> lchild );}

(6) 后序后继的求解
分析:
(a) 根 —— 无后继;
(b) 若*p是其父结点的右孩子 —— 父结点是其后继;
© 若是父结点的左孩子 ——
无右兄弟 —— 父结点是其后继;
有右兄弟
—— 右兄弟子树的后序序列的第一个结点是其后继
——右兄弟子树中最左下的叶子结点。

线索二叉树中插入结点

在结构中插入一个元素或结点是常见的运算。
在线索二叉树中插入一个结点时,不仅要实现指定结点的父子关系的运算,还需要在插入结点后,通过修改线索,以维护二叉树的线索关系。例如,在右图线索二叉树中,将某结点插入到作为结点F的左孩子。
如何实现相关的操作?
分析:对这类插入操作,通常从两个方面来考虑其实现:
(1)一个是父子关系的连接实现
按照指定关系连接即可
(2)线索关系的维护
这一关系的实现有一定的难度。

下面分别讨论。
(1)父子关系的连接实现
对前述问题,由问题描述可知,
假设指针P指示到了F结点,
连接操作如图所示,操作如下:
p->lchild=s;
p->ltag=0;

(2)线索关系的维护
这一操作主要由如下组成:
(某些操作可能因具体问题而不同)
设置新插入结点的前驱、后继线索
修改新结点的前驱结点的后继线索
修改新结点的后继结点的前驱线索
例如,在右图线索二叉树中,
将某结点插入到作为结点F的左孩子。
如何实现相关的操作?

下面先讨论线索操作的一般性方法,
然后给出本题的操作实现。假设当前结点为P,由于线索关系使得结点之间建立了线性关系,因此,插入结点时的线索维护类似于双链表中插入结点。由于新结点是作为P的后继,
因此,可有如下的逻辑图:

. 二叉树的线索化算法实现

——先序线索化为例
前驱结点的后继线索化;
当前结点的前驱线索化;
判断当前结点是否需要后继线索化

void prethread( bnode * t, bnode * pre){ if  ( t != NULL ){if (( pre != NULL ) && ( pre->rtag==1))  pre->rchild=t;if  ( t->lchild == NULL ) { t->lchild = pre; t->ltag=1;}else t->ltag=0;if ( t->rchild == NULL ) t->rtag=1;else t->rtag=0;pre = t;if ( t->ltag==0) prethread( t->lchild, pre); if ( t->rtag==0) prethread( t->rchild, pre);   }
}

遍历线索二叉树

//利用前面的寻找前驱和后继节点的算法 中序
void inOrder()
{if(root !=NULL)
{ThreadBTNode<DataType>*s = root;
while(prior(s)!=NULL)
{s = prior(s);//找到起始结点
}
while(succ(s)!=NULL)
{cout<<s->data<<" ";
s = succ(s);//从起始结点开始遍历节点
}
}

18.分块查找

基本思想:先插索引表,利用顺序查找或者二分查找确定待查关键字k,属于哪一个块
根据索引表中块首记录的地址找到主表中块的起始地址,利用顺序查找的方法查找k,如果找到则返回地址,否则返回null

【练习】2021下半年数据结构刷题笔记和总结 (二) 树、查找-- 不同的排序算法、二叉排序树 平衡二叉树、哈希表查找、线索二叉树、相关推荐

  1. 【练习】2021下半年数据结构刷题笔记和总结 (三)栈 队列 链表 枚举算法

    题目来自书或者网站. 解密QQ 号--队列 回文字符串---栈 火柴棍等式 输入数字n,要求输出从1~n的全排列 [力扣]给你一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 ...

  2. 【练习】2021下半年数据结构刷题笔记和总结 (一)(图和动态规划)

    文章目录 1.编程将一个字符串中所有空格替换为"%20" 2.定两个字符串,判断一个字符串是否是另一个字符串的排列 3.求一个房间内有数个钩子,给定一定长度的绳索,要把所有的钩子用 ...

  3. 图解算法数据结构刷题笔记02

    系列文章目录 图解算法数据结构刷题笔记01 本篇文章目录 系列文章目录 前言 1.剑指 Offer 05. 替换空格 2.剑指 Offer 06. 从尾到头打印链表 3.剑指 Offer 09. 用两 ...

  4. 【2021/5/17 刷题笔记】买卖股票的最佳时机与动态规划

    文章目录 买卖股票的最佳时机 [题目] [我的方法] 执行结果: 动态规划算法 1.状态定义 2.设置数组边界值 3.推导状态转换方程. 参考代码 执行结果: 复杂度分析: 时间复杂度 空间复杂度 * ...

  5. 【2019暑假刷题笔记-STL绪论(二)】总结自《算法笔记》

    目录 五.queue的常见用法 六.priority_queue的常见用法 七.stack的常见用法 八.algorithm头文件下的常用函数 五.queue的常见用法 queue也就是队列,是STL ...

  6. 面试刷题必看!Python中的5大排序算法及其实现代码

    排序是每个 IT 工程师和开发人员必备的知识技能.不仅要通过编程面试,而且要了解算法本身.不同的排序算法完美地展示了算法设计如何对程序的复杂性.速度和效率产生如此大的影响. 让我们来看看排名前5,也是 ...

  7. Google 资深软件工程师 LeetCode 刷题笔记首次公开

    BAT 等国内的一线名企,在招聘工程师的过程中,对算法和数据结构都会重点考察.但算法易学难精,我的很多粉丝技术能力不错,但面试时总败在算法这一关,拿不到好 Offer.但说实话,数据结构和算法花点时间 ...

  8. 刷题笔记(十四)--二叉树:层序遍历和DFS,BFS

    目录 系列文章目录 前言 题录 102. 二叉树的层序遍历 BFS DFS_前序遍历 107. 二叉树的层序遍历 II BFS DFS 199. 二叉树的右视图 BFS DFS 637. 二叉树的层平 ...

  9. 一夜登顶GitHub!字节内网数据结构与算法刷题笔记,看完直呼卧槽

    网络上流传着一句段子"程序员两条腿,一条是算法,一条是英文,想跑的更远,这两条腿都不能弱".英文,我们暂且不谈,我们先来谈谈算法. 算法之难,在于将精巧的逻辑,通过合适的数据结构, ...

最新文章

  1. 一步一步学习VirtualBox安装CentOS7和CentOS8
  2. OSError: [WinError 6] 句柄无效
  3. 【PC工具】更新简单好用绿色IP地址扫描工具,内部网络设备查看工具,内网ip查询ip扫描工具,电脑IP地址查看方法...
  4. java实现随机验证码的图片
  5. 2.2 《数据库系统概论》之关系操作、关系完整性、关系代数
  6. Android studio 关于SQlite数据库导出,创建数据库、表以及如何查看操作
  7. aliyun的maven下载jar的方法
  8. threadlocal线程_线程故事:Web应用程序中的ThreadLocal
  9. HP-JavaUtil: xls 操作类
  10. android4以上版本读写外置sd卡报错的解决办法
  11. RVA和文件偏移的转换
  12. c语言中函数的递归调用,用C语言函数调用与递归解决问题
  13. python是一种什么类型的高级语言_python介绍 编程语言分类及对比 python解释器安装(多版本共存) 变量 数据类型(三种)...
  14. JAVA毕业设计河南口腔医疗机构线上服务系统计算机源码+lw文档+系统+调试部署+数据库
  15. idea toggle offline mode
  16. 零基础入门,资深吃货带你搞懂大数据
  17. android BKS
  18. denoted(denoted by)
  19. Composer中的ThingWorx模型定义—可视化
  20. python定时开关机的代码_python实现Windows电脑定时关机

热门文章

  1. python3库下载_下载安装Python第三方库的方法,最全方式,值得收藏
  2. 【转】SSM框架搭建流程与解析
  3. 邯郸学院计算机专业是本科还是专科,邯郸学院是大学吗 是本科还是专科
  4. uwsgi指定python路径_uWsgi服务器(2)--安装配置
  5. java动态生成柱状图3D_在android上动态实现ichartjs的3D柱形图
  6. 【机器学习算法专题(蓄力计划)】十八、机器学习中SVM算法中的硬间隔和软间隔
  7. 第一次接广告的心得,关于广告我怎么看
  8. 物理化学 化学 动力学(下)
  9. keras从入门到放弃(十一)电影评价预测
  10. 从2019年-2021年的各大顶会论文,看动态神经网络的发展