puppypop

导航

 

#include<stdio.h>
#include<stdlib.h>

//树与二叉树
//31已知一颗二叉树按顺序存储结构进行存储,设计一个算法,
//求编号分别为i和j的两个结点的最近公共祖先结点的值
/*算法思想:
顺序存储结构的适用范围:完全二叉树和满二叉树;
对于普通二叉树,可用空指针结点补充转换为完全二叉树;
顺序存储二叉树,数组从1开始标号;
不断的将较大的取一半,比较i和j的大小,直到i=j,表明找到了公共祖先结点
*/

elemtype Com_Ancestor(SqTree T,int i,int j)
{
if(T[i]!=null&&T[j]!=null)
{
while(i!=j)
{
if(i>j)
i=i/2;
else
j=j/2;
}
}
return T[i];
}

//32二叉树的遍历,先序、中序、后序
/*算法思想:
visit的位置;
递归:在函数体内调用自身
无论采用哪种遍历算法,所有结点都访问一次且仅访问一次,时间复杂度为O(n),
最坏的空间复杂度为退化成单分支树,为O(n)
*/

//二叉树的链式存储结构
typedef struct BiTNode{
elemtype data;
struct BiTNode *lchild,*rchild;
}BiTNode,*BiTree;

//先序遍历
void preorder(BiTree T)
{
if(T!=null)
{
visit(T);
preorder(T->lchild);
preorder(T->rchild);
}
}
//中序
void inorder(BiTree T)
{
if(T!=null)
{
inorder(T->lchild);
visit(T);
inorder(T->rchild);
}
}

//后序
void postorder(BiTree T)
{
if(T!=null)
{
postorder(T->lchild);
postorder(T->rchild);
visit(T);
}
}

//总结
void Funorder(BiTree T)
{
if(T!=null)
{
//操作
Funorder(T->lchild);
//操作
Funorder(T->rchild);
//操作
}

 

 

//33中序遍历的非递归算法
/*口诀:入栈向左一直走,出栈访问右子树,p空栈空才结束。
算法思想:
1.沿着根的左孩子,依次入栈(先进先出)直至左孩子为空,
2.将栈顶元素出栈并访问,若出栈的结点的右孩子也为空,则继续出栈栈顶元素并访问
3.否则则执行1
*/


void InOrder2(BiTree T) {
InitStack(S);
BiTree p = T;
while (p != NULL || !IsEmpty(S)) {//p空栈空才结束
if (p) {
push(S, p);//入栈
p = p->lchild;//一路向左走
}
else {
pop(S, p);//找到二叉树最左边的结点,出栈
visit(p);//访问
p = p->rchild;//右子树
}
}
}

//34后序遍历的非递归算法
/*算法思想:
1.沿着根的左孩子,依次入栈,直至左孩子为空
2.读栈顶元素(进行判定),若其右孩子不空且未被访问过,将右子树进行相同12处理(将右孩子执行1)
3.栈顶元素出栈
*/


bool GetTop(SqStack S, ElemType& x) {
if (S.top == -1) {
return false;
}
x = S.data[S.top];//x记录栈顶元素
return true;
}
void PostOrder(BiTree T) {
InitStack(S);
p = T;
r = NULL;//r指针标记最近访问的结点
while (p || !IsEmpty(S)) {
if (p) {
Push(S, p);
p = p->lchild;
}
else {
GetTop(S, p);//读取栈顶结点
//读栈顶元素的作用就是找下一个结点
if (p->rchild != NULL && p->rchild != r) {
//如果右子树不为空且未被访问过,执行1的操作
p = p->rchild;
push(S, p);
p = p->lchild;
}
else {
pop(S, p);
visit(p->data);
r = p;
//当递归到最左边的叶子结点入栈,出栈并访问后,此时的P还指向它,
//此时应对P置空,否则就又把它压进栈里面了
//不重置,栈顶元素会无限入栈出栈
//因为要去出栈了 p=null后if就不成立了了,直接调到else在出栈
//因为要判断栈顶,p不为空不能执行else里面的gettop
p = NULL;//结点已经出栈,置空处理
}
}
}
}

//35二叉树层次遍历算法
/*算法思想:利用队列
1.将根结点入队,出队,访问出队的结点,若它有左孩子,则将左孩子入队,若它有右孩子,则将右孩子入队
2.然后出队,接着判定
直至队为空
*/

void levelOrder(BiTree T)
{
InitQueue(Q); //初始化队列
BiTree p = T;
EnQueue(Q, T); //将根结点入队
while (!isEmpty(Q)) //队不空则重复进
{
DeQueue(Q, p); //出队
visit(p);
if (p->lchild != null) //若有左孩子则左孩子入队
EeQueue(Q, p->lchild);
if (p->rchild != null) //若有右孩子则右孩子入队
EeQueue(Q, p->rchild);
}
}

//36试给出二叉树自下而上,从右到左的层次遍历算法
/*算法思想:利用原本的层次遍历算法,出队的同时将各结点入栈再依次出栈
*/

void LevelOrder(BiTree T) {
Stack s; Queue q;
if (T != NULL) {
InitQueue(Q);
InitStack(S);
BiTree p =T;
Enqueue(Q, T);
while (!IsEmpty(Q)) {
DeQueue(Q, p);
push(S, p);
if (p->lchild) {
Enqueue(Q, p->lchild);
}
if (p->rchild) {
Enqueue(Q, p->rchild);
}
}
while (!IsEmpty(S)) {
pop(S, p);
visit(p->data);
}
}
}

//37假设二叉树采用二叉链表存储结构,设计一个算法求二叉树的高度(递归和非递归)
/*递归的算法思想:递归求解左子树高度和右子树高度,取较大者加1
*/
int Btdepth2(BiTree T)
{
if (T == null)
return 0; //空树高度为0
ldep = Btdepth2(T->lchild); //调用函数求左子树高度
rdep = Btdepth2(T->rchild); //求右子树高度
if (ldep > rdep)
return ldep + 1;
else
return rdep + 1;
}

/*37.2非递归的算法思想:层次遍历的改进
设置level记录二叉树的层数,设置指针last指针指向最右结点,只要当front==last时即可
*/
int Btdepth(BiTree T)
{
if (!T)
return 0;
int front = -1, rear = -1;
int last = 0, level = 0;
BiTree Q[MaxSize];
Q[++rear] = T; //根结点入队
Bitree p;
while (front < rear)
{
p = Q[++front]; //将p出队
if (p->lchild != null);
Q[++rear] = p->lchild;
if (p->rchild != null)
Q[++rear] = p->rchild;
if (front == last) //last始终指向最右结点
{
level++;
last = rear;
}
}
return level;
}

//38设树B是一颗采用链式存储的二叉树,编写一个把树中所有结点的左右子树交换的函数。
/*算法思想:递归的交换左右子树
*/
void swap(BiTree b)
{
if (b)
{
swap(b->lchild); //递归的交换左子树
swap(b->rchild); //递归的交换右子树
BiTreeNode* temp = b->lchild;
b->lchild = b->rchild;
b->rchild = temp;
}
}

//39假设二叉树采用二叉链表存储结构存储,设计一个算法,计算一颗给定二叉树的所有双分支的结点个数
/*算法思想:递归,看其本身是空、度为1、度为2
*/
int DoubleNodes(BiTree b)
{
if (b == null)
return 0;
else if (b->lchild != null && b->rchild != null)
return DoubleNodes(b->lchild) + DoubleNodes(b->rchild) + 1;//加一是加其本身
else //b->lchild==null||b->rchild==null 本身是度为1的结点
return DoubleNodes(b->lchild) + DoubleNodes(b->rchild);
}

//39.2思考题:统计二叉树度为1的结点个数
int Degree_1(BiTree b) {
if (b == NULL) {
return 0;
}
else if (b->lchild != NULL && b->rchild != NULL) {
return Degree_1(b->lchild) + Degree_1(b->rchild);
}
else {
return Degree_1(b->lchild) + Degree_1(b->rchild) + 1;
}
}
//39.3思考题:统计二叉树度为0的结点个数
int NumsDegree_0(BiTree T)
{
if (T != NULL)
{
if (T->left == NULL && T->right == NULL)
return 1;
else
return NumsDegree_0(T->left) + NumsDegree_0(T->right);
}
else
return 0;
}

//40计算二叉树中所有结点的个数
/*算法思想:递归法 F(n)=F(左子树)+F(右子树)+1
*/

int count(BTNode* p)
{
int n1, n2;
if (p == null)
return 0;
else
{
n1 = count(p->lchild);
n2 = count(p->rchild);
return n1 + n2 + 1;
}
}

//40.2算法思想:遍历法,以先序为例中设置一个计数
int n = 0;
int count(BTNode* p)
{
if (p != null)
{
++n; //将访问p改写成计数加一
count(p->lchild);
count(p->rchild);
}
}

//41假设二叉树采用二叉链表存储结构存储,设计一个算法,求先序遍历序列中第k(1<=k<=二叉树中结点个数)个结点的值
/*算法思想:先序遍历二叉树,求第k个结点
*/

int n = 0;//定义全局变量
int trave(BTNode* p, int k)
{
if (p != null)
{
++n; //计数
if (k == n) //在先序遍历计数的基础之上加一个判断语句
return print("%d", p->data);
trave(p->lchild, k);
trave(p->rchild, k);
}
}

//42计算二叉树中所有叶子结点的个数
/*算法思想:递归求解
*/

int count(BTNode* p)
{
int n1, n2;
if (bt = null)
return 0;
if (p->lchild == null && p->rchild == null)
return 1;
n1 = count(p->lchild);
n2 = count(p->rchild)
return n1 + n2;
}

//42.2 算法思想:遍历法(以先序遍历为例)
int count2(BTNode* p)
{
int n;
if (p != null)
{
if (p->lchild == null && p->rchild == null) //visit(p);
++n;
count2(p->lchild);
count2(p->rchild);
}
}

//43找二叉树中data域等于key的结点是否存在,若存在,则q向它,否则q为空
/*算法思想:建立在遍历的基础上,在遍历的过程中,寻找符合条件的点
*/

void fun(BTNode* p, BTNode* q, int key)
{
q = null;
if (p != null)
{
if (p->data == key)
q = p;
else
{
fun(p->lchild, q, key);
fun(p->rchild, q, key);
}
}
}

//44利用结点的右孩子指针将一个二叉树的叶子结点从左向右链接成一个单链表(head指向第一个,tail指向最后一个)
/*算法思想:
1.找到叶子节点
2.连成单链表
*/

void link(BT* p, BT* head, *tail)
{
if (p != null)
{
if (p->lchild = null && p->rchild == null)
if (head == null) //初始head为空,要将第一个叶子结点存入
{
head = p;
tail = p;
}
else
tail->rchild = p; //后面陆续链接就可,tail->rchild=p;相当于tail->next=p;
tail = p;
}
link(p->lchild, head, tail);
link(p->rchild, head, tail);
}

//45若二叉树采用链式存储结构,设求出指定结点在给定二叉排序树的层次
/*算法思想:如果根结点不为空,则将指定结点的数和树中的结点值作比较,用t遍历,用n记录层次
*/

int level(BTNode* bt, BTNode* p) {
int n = 1;
BTNode* t = bt;//遍历指针
if (bt != NULL) {
while (t->data != p->data) {
if (t->data < p->data) {
t = t->rchild;
}
else {
t = t->lchild;
}
++n;
}
}
return n;
}

//46二叉树的带权路径长度(WPL)是二叉树中所有叶节点的带权路径之和,给定一颗二叉树T,
//采用二叉链表存储,结点结构为 left,weight,right 其中叶节点的weight域保存该结点的非负权值,设root为指向T的根节点的指针,请设计求T的WPL的算法
/*算法思想:将所有叶子结点的WPL累加就可以了,采用先序递归
*/

int WPL_preorder(BiTree root, int deep)
{
int WPL = 0;
//visit(p);
if (root->lchild == null && root->rchild == null) //若为叶节点,则累计WPL
WPL = WPL + deep * root->weight;
//preorder(T->lchild);
if (root->lchild != null) //若左子树不为空,则左子树递归遍历
WPL_preorder(root->lchild, deep + 1);//因为往下走一层,所有层数deep需要加一
//preorder(T->rchild);
if (root->rchild != null)
WPL_preorder(root->rchild, deep + 1);
return WPL;
}
int WPL(BiTree root)
{
return WPL_preorder(root, 0); //从深度0开始调用
}

//47请设计一个算法,将给定的表达式(二叉树)转换为等价的中缀表达式(通过括号反映操作符的计算次序)并输出
/*算法思想:
1.使用中序(中缀表达式)
if(p!=null)
{
//Inorder(T->lchild);
//visit(T);
//Inorder(T->rchild);
}
2.括号如何加——
①根结点不加括号
②叶子结点不加括号
③其他结点都需要加,中序访问左子树之前加,中序访问右子树之后加
*/

void Inorderfun(BiTree* root, int deep)
{
if (root == null)
return;
else if (root->lchild == null && root->rchild == null) //叶子结点则直接输出,不用加括号
printf("%s", root->data);
else
{
if (deep > 1) //说明有孩子,属于非叶子结点则需要加上括号,中序访问左子树之前加括号
{
printf("(");
}
Inorderfun(root->left, deep + 1); //层次加一 Inorder(T->lchild);
printf("%s", root->data); //visit(T);
Inorderfun(root->right, deep + 1) //Inorder(T->rchild);
if (deep > 1) //中序访问右子树之后加括号
{
printf(")");
}
}
}
void fun(BiTree* root)
{
Inorderfun(root, 1); //根结点高度层次为1
}

//48假设二叉树采用二叉链表结构存储,设计一个算法,求二叉树中值为x的层号
/*算法思想:
1.使用遍历
2.用h记录层数,遍历时设计加一和减一操作
当访问一个新的孩子结点时需要加一,当从所访问孩子结点回到父节点时需要减一
*/

int h = 1;
void fun(BTNode* p, int x)
{
if (p != null)
{
if (p->data == x)
print("%d", h);
++h; //进入左子树+1,向下走
fun(p->lchild, x);
fun(p->rchild, x);
--h; //出右子树-1,向上走
}
}

//49请设计一个算法,增加一个指向双亲结点的parent指针,并给指向的指针赋值,并输出所有结点到根结点的路径
/*算法思想:
1.增加parent方便找父亲;
2.先解决单个结点到根结点
3.遍历整个树,反复递归第二步
*/

//增加parent指针
void fun(BTNode* p, BTNode* q)
{
q->parent = null;
if (p != null)
{
p->parent = q;
q = p;
fun(p->lchild);
fun(p->rchild);
}
}
//单个结点到根结点的路径
void printpath(BTNode* p)
{
while (p != null)
{
print("%c", p - data);
p = p->parent;
}
}

//遍历整个树,输出所有路径
void allpath(BTNode* p)
{
if (p != null)
{
printpath(p); //visit(p)
allpath(p->lchild);
allpath(p->rchild);
}
}

//50已知一颗二叉树链式存储结构,请设计一个算法,输出根结点到每个叶子结点的路径
/*算法思想:
1.使用先序遍历进行(中序和后序也可以)
2.对特殊结点(叶子结点)处理
1.使用栈实现
*/

void path(BTNode* p)
{
int i = 0, top = 0; //最开始栈在0,所以可以先入栈再移动指针
ElemType Stack[maxSize]; //初始化栈
if (p != null) //不空,结点值入栈
{
Stack[top] = p->data; //入栈元素
++top;
}
if (p->lchild == null && p->rchild == null) //叶子结点需要读出栈数据(不是出栈)
{
for (int i = 0; i < top; ++i) //从栈底开始读
printf("%c", Stack[i]);
}

path(p->lchild); //遍历左子树
path(p->rchild); //遍历右子树
--top; //每次访问完右子树后要进行指针后退,退回其父节点
}

 

//51广度优先遍历(BFS)
/* 算法思想:
- 找到与一个顶点相邻的顶点;
- 标记哪些顶点被访问过(visited[]数组);
- 需要一个辅助队列;
- 图的基本操作;
- FirstAdjVex(G,v):求图G中顶点的第一个邻接点,若存在,则返回顶点号,若v不存在邻接点或者图中不存在x,则返回-1;
- NextAdjVex(G,v,w):图G中顶点v在w之后的下一个邻接点,若存在,则返回顶点号,若v不存在或者图中不存在x,则返回-1。
类似于层次遍历
口诀:入队出队找邻居,访问标记入队*/

void BFS(Graph G, int v) //图G,开始顶点v
{
InitQueue(Q); //初始化队列
for (int i = 0; i < G.vexnum, ++i) //初始化标记访问数组
visited[i] = 0;

visit(v);//访问初始顶点
visited[v] = 1; //访问位标记为1
EnQueue(Q, v); //将v入队
while (!isEmpty(Q)) //当队不空 出队
{
DeQueue(Q, v);
}
for (w = FirstAdjVex(G, v); w >= 0; w = NextAdjVex(G, v, w)) //检测v的所有邻接点,直到没有更多的邻接顶点为止(即 w 变为 -1)
{
if (visited[w] == 0) //未被访问则访问
{
visit(w); //访问
visited[w] = 1; //标记
EnQueue(Q, w); //入队
}
}
}

//以下不做要求,可直接使用函数
//求图G中顶点的第一个邻接点,若存在,则返回顶点号
int FirstAdjVex(Graph G, int v)
{
int i;
for (i = 0; i < G.vexnum; ++i) //G.vexnum顶点数
{
if (G.arcs[v][i].adj) //arcs邻接矩阵中v行i列的权值(不为空即v和i存在边)
{
return i;
}
}
return -1; //没有邻接点返回-1
}

//图G中顶点v在w之后的下一个邻接点,若存在,则返回顶点号
int NextAdjVex(Graph G, int v, int w)
{
int i;
for (i = w + 1; i < G.vexnum; ++i)
{
if (G.arcs[v][i].adj == 1)
{
return i;
}
}
return -1;
}

//52深度优先算法(DFS)
/*算法思想:
1.递归算法,时间复杂度:O(顶点数)
时间复杂度:邻接矩阵O(v^2)
邻接矩阵O(v+e);
2.需要visited数组标记访问位
3.需要栈的辅助一条路走到底,完成回溯
类似于先序遍历
*/

void DFS(Graph G, int v) //传入参数,图G和v,从顶点v出发
{
visit(v);
visited[v] = 1;
for (w = FirstAdjVex(G, v); w >= 0; w = NextAdjVex(G, v, w)) //检测到v的邻接点
{
if (visited[w] == 0) //邻接结点未被访问
{
DFS(G, w);
}
}
}

//53图的邻接表的存储结构定义

//图的邻接表存储结构
//边表
typedef struct ArcNode
{
int adjvex; //邻接顶点,就是这条边所对应的顶点
struct ArcNode* nextarc; //指向下一个边结点的指针
}ArcNode;

//顶点表
typedef struct VNode
{
VexType data; //顶点表的数值
ArcNode* firstarc; //取顶点引出的第一条边
}VNode;

//图结构体
typedef struct //图结构体
{
VNode adjList[maxSize]; //将图的顶点数据放在一个数组中
int vexnum, arcnum; //顶点和边的个数
}Graph;

//应用
k = p.adjvex;//取p指针指向的结点的值
p = G->adjList[k].firstarc;//取第k个位置的第一个指针

//54拓扑排序-判断有向图是否存在回路
/*算法思想:
1、选择一个入度为0的顶点并输出(不唯一)
2、从图中删除入度为0的顶点并输出
3、循环进行12,循环结束时,如果输出的顶点数小于图中顶点数,则存在回路,否则,输出的顶点数为拓扑排序的序列
*/

bool TuoPuSort(Graph G)
{
InitStack(S); //初始化栈
for (int i = 0; i < G.Vexnum; ++i) //选择入度为0的顶点入栈
{
if (indegree[i] == 0) //入度为0
push(S, i);
}
int count = 0;
while (!isEmpty(S)) //栈不空则出栈
{
pop(S, i)
count = i;
cout << count;
count++;
}
for (p = G.vertices[i].firstarc; p != null; p = p->nextarc)
//(邻接表中i顶点引出的第一条边;p不为空;p=p引出的边指向下一个边结点的指针)
{
v = p->adjvex;
if (!(--indegree[v] )) //入度为0的顶点则入栈
push(S, v);
}
if (count < G.vexnum) //有回路
return false;
else //拓扑排序成功
retrun true;
}

 


//55快速排序
/*算法思想:分治法
1.首先写一轮排序的代码
2.反复递归(分治思想)
*/
//一轮快排
int pivot(ElemType A[], int low, int high)
{
//将基准元素保存下来
temp = A[low];
while (low < high)
{
while (A[high] >= temp && low < high) //从high开始,找比temp小的元素
--high;
A[low] = A[high];
while (A[low] < temp && low < high) //从low开始,找比temp大的元素
++low;
A[high] = A[low];
}
A[low] = temp;
return low;//返回最终枢轴所在位置,以便下一轮
}
//反复递归(分治思想)
void QuickSort(ElemType A[], int low, int high)
{
if (low < high)
{
int temp = pivot(A, low, high); //因为返回了最终枢轴的位置,所以就得到了第二轮划分的位置
QuickSort(A, low, temp - 1);
QuickSort(A, temp + 1, high);
}
}

posted on   不敢想象thisvibe  阅读(45)  评论(2编辑  收藏  举报
努力加载评论中...
 
点击右上角即可分享
微信分享提示