一、线性表
1.1 顺序表
- 顺序表的结构描述
typedef struct
{
int data[maxSize];
int length;
}Sqlist;
- 插入元素
int insertElem(int A[],int &len,int p,int k) //考试中顺序表常用方式(一般不使用结构体) p为要插入的位置,k为插入值
{
int i;
if(p<0 || p>len || len==maxSize)
return 0;
for(i=len-1;i>=p;i--)
{
A[i+1]=A[i];//元素后移
}
A[p]=k;
len++;
return 1;
}
- 删除元素
int delElem(int A[],int &len,int p)
{
int i;
if(p<0 || p>len-1)
return 0;
for(i=p;i<len-1;i++) //注意i<len-1,不需要让i到达最后一个元素
A[i]=A[i+1]; //前移
--len;
return 1;
}
1.2 单向链表
#include <iostream>
using namespace std;
//类型描述
typedef struct LNode
{
int data;
struct LNode *next;
}LNode;
//尾插法创建
void createlistR(LNode *&C,int a[],int n)
{
LNode *s,*r;//r是尾指针,s指向每一次的新节点
int i;
C=(LNode *)malloc(sizeof(LNode));
C->next=NULL;
r=C;
for(i=0;i<n;i++)
{
s=(LNode*)malloc(sizeof(LNode));
s->data=a[i];
s->next=NULL;
r->next=s;
r=s;
}
}
//头插法创建
void createlistF(LNode *&C,int a[],int n)
{
//关键代码:
LNode *s;
s->data=a[i];
s->next=C->next;
C->next=s;
}
//插入节点
void insert()
{
//keycode:
LNode *s,*p;
s->next=p->next;
p->next=s;
}
//删除节点
void del(LNode *L)
{
//关键代码:
LNode *p,*q;//删除p的后继
q=p->next;
p->next=q->next;
free(q);
}
int main()
{
return 0;
}
1.3 单向循环链表
#include <iostream>
using namespace std;
//类型描述
typedef struct LNode
{
int data;
struct LNode *next;
}LNode;
// 初始化
int init(LNode *&L)
{
L=(LNode *)malloc(sizeof(LNode));
L->next=L;
}
// 插入节点
int insert(LNode *L,int i,int x)//插入到第i-1到i个位置之间
{
LNode *p;
int pos;
// 让p指向第i-1个节点
while(p->next!=L && pos<i-1) //注意结束条件
{
p=p->next;
pos++;
}
if(p->next==L && pos<i-1||pos>i-1)
return 0;
LNode *s=(LNode*)malloc(sizeof(LNode));
s->data=x;
s->next=p->next;
p->next=s;
return 1;
}
// 删除节点
int del(LNode *L,int i,int x) //删除第i个节点
{
LNode *p;
int pos=0;
//让p指向第i-1个节点
while(p->next!=L && pos<i-1)
{
p=p->next;
pos++;
}
if(p->next==L || pos>i-1)
return 0;
LNode *q=p->next;
p->next=q->next;
free(q);
return 1;
}
1.4 双向循环链表
#include <iostream>
using namespace std;
//类型描述
typedef struct DLNode
{
int data;
struct DLNode *prior;
struct DLNode *next;
}DLNode;
// 初始化
int init(DLNode *L)
{
L=(DLNode*)malloc(sizeof(DLNode));
L->next=L->prior=L;
}
// 插入节点
int insert(DLNode *L,int i,int x)
{
DLNode *p=L,*s;
int j=0;
// 让p指向第i-1个结点
while(p->next!=L && j<i-1)
{
p=p->next;
j++;
}
if(p->next==L && j<i-1||j>i-1)
return 0;
DLNode *s=(DLNode*)malloc(sizeof(DLNode));
s->data=x;
s->prior=p;
s->next=p->next;
p->next->prior=s;
p->next=s;
return 1;
}
//删除结点
inr del(DLNode *L,int i,int x)
{
DLNode *p,*q;
// 让p指向第i-1个节点
p=L;
int j=0;
while(p->next!=L && j<i-1)
{
p=p->next;j++;
}
if(p->next==L||j>i-1)
return 0;
q=p->next;
p->next=q->next;
q->next->prior=p;
free(q);
return 1;
}
//遍历
void disp(DLNode *L)
{
// 后继遍历
DLNode *p=L->next;
while(p!=L) //结束条件
{
p=p->next;
}
// 前驱遍历
p=L->prior;
while(p!=L)
{
p=p->next;
}
}
int main()
{
return 0;
}
1.5 线性表的应用
1.5.1 两个线性表的合并
#include <iostream>
using namespace std;
typedef struct LNode
{
int data;
struct LNode *next;
}LNode;
/*方法一假设合并的链表上的结点空间是原来的空间,其算法设计的主要思想是将
其中一个链表上的结点逐个插人到另一个链表中。*/
void merge1(LNode *La,LNode *Lb)//合并到La
{
LNode *pa,*pb,*qa,*qb;
q=La;pa=La->next;pb=qb=Lb->next;
while(pa&&pb)
{
if(pb->data<=pa->data)//插入到qa和pa之间 (qa始终是pa的前驱结点)
{
qb=qb->next;//key
pb->next=pa;
qa->next=pb;
pa=qa->next;//key error 调整pa,让其前驱为qa
pb=qb;//key
}
else
{
qa=pa;
pa=pa->next;
}
}
if(pb) qa->next=pb;//剩余结点
free(Lb);
}
/*
方法二假设合并的链表上的结点空间是重新申请的空间,其算法设计的主要思想是
将原来的两个链表上的结点依次比较逐个插入到新链表中。
*/
void merge2(LNode *La,LNode *Lb,LNode *&Lc)
{
LNode *pa,*pb,*pc,*s;
pa=La->next;
pb=Lb->next;
Lc=(LNode*)malloc(sizeof(LNode));
pc=Lc;
while(pa&&pb)
{
if(pb->data<=pa->data)
{
s=(LNode*)malloc(sizeof(LNode));
s->data=pb->data;
s->next=NULL;
pc->next=s;
pc=s;
pb=pb->next;//后移
}
else
{
s=(LNode*)malloc(sizeof(LNode));
s->data=pa->data;
s->next=NULL;
pc->next=s;
pc=s;
pa=pa->next;//后移
}
}
//收尾
while(pb)
{
s=(LNode*)malloc(sizeof(LNode));
s->data=pb->data;
s->next=NULL;
pc->next=s;
pc=s;
pb=pb->next;
}
while(pa)
{
s=(LNode*)malloc(sizeof(LNode));
s->data=pa->data;
s->next=NULL;
pc->next=s;
pc=s;
pa=pa->next;
}
}
int main()
{
return 0;
}
1.5.2 一元函数的求和与求积
#include <iostream>
using namespace std;
//类型描述
typedef struct
{
float coef;//存放系数
int exp;//存放指数
}Term;
typedef struct Pnode
{
Term data;
struct Pnode *next;
}Pnode;
//插入节点
void insert(Pnode *L,Term x)
{
Pnode *p=L,*q=L->next,*s;//p q 记住相邻的两个结点
while(p)
{
if(q!=NULL && x.exp>p->data.exp && x.exp<q->data.exp) //插入到p、q之间
{
s=(Pnode*)malloc(sizeof(Pnode));
s->data=x;
s->next=q;
p->next=s;
return;
}
else if(q!=NULL && x.exp==q.data.exp)
{
if(fabs(q.data.coef + x.coef) < 1.0E-6) //指数相等,系数符号相反,绝对值相等
{
p->next=q->next; //删除q结点
free(q);
return ;
}
else
{
q->data.coef = x.coef + q->data.coef; //指数相等,系数不同,合并
return ;
}
}
else if(q==NULL && x.exp > p->data.exp) //插入到最后
{
s=(Pnode*)malloc(sizeof(Pnode));
s->data=x;
s->next=NULL;
p->next=s;
return;
}
else //后移,寻找插入位置
{
p=q;
q=q->next;
}
}
}
//两个一元函数多项式的加法
void add(Pnode *La,Pnode *Lb,Pnode *Lc)
{
Pnode *s,*pa,*pb,*pc;
Lc=(Pnode*)malloc(sizeof(Pnode));
Lc->data.exp=-1;
Lc->next=NULL;
pa=La->next;
pb=Lb->next;
pc=Lc;
while(pa&&pb)
{
if(pa->data.exp < pb.data.exp)
{
s=(Pnode*)malloc(sizeof(Pnode));
s->data=pa->data;
s->next=NULL;
pc->next=s;
pc=s;
pa=pa->next;//后移
}
else if(pa->data.exp == pb->data.exp)//合并同类项
{
if(fabs(pa->data.coef + pb->data.coef) > 1.0E-6)//之后和不为零才会插入
{
s=(Pnode*)malloc(sizeof(Pnode));
s->data.coef = pa->data.coef + pb->data.coef;
s->data.exp = pa->data.exp;
s->next = NULL;
pc->next=s;
pc=s;
}
pa=pa->next;
pb=pb->next;
}
else
{
s=(Pnode*)malloc(sizeof(Pnode));
s->data=pb->data;
s->next=NULL;
pc->next=s;
pc=s;
pb=pb->next;
}
}
while(pa)
{
s=(Pnode*)malloc(sizeof(Pnode));
s->data=pb->data;
s->next=NULL;
pc->next=s;
pc=s;
pa=pa->next;
}
while(pb)
{
s=(Pnode*)malloc(sizeof(Pnode));
s->data=pb->data;
s->next=NULL;
pc->next=s;
pc=s;
pb=pb->next;
}
}
//乘法
/*
将第1个一元多项式的每一项与第2个一元多项式的各项相乘,再插人到新的一元
多项式中。
*/
void mul(Pnode *La,Pnode *Lb,Pnode *Lc)
{
Pnode *pa,*pb;
Term x;
Lc=(Pnode*)malloc(sizeof(Pnode));
Lc->data.exp=-1;
Lc->next=NULL;
pa=La->next;
while(pa)
{
pb=Lb->next;
while(pb)
{
x.coef = pa->data.coef * pb->data.coef;//系数相乘
x.exp = pa->data.exp + pb->data.exp;//指数相加
insert(Lc,x);
pb=pb->next;
}
pa=pa->next;
}
}
int main()
{
return 0;
}
二、栈和队列
2.1 表达式求值的两种方法
[分析]后缀表达式是一个字符串,为了方便处理,以’#‘结束。用一个栈(假定数据元素类型为整型)来存放操作数和中间的计算结果。对后缀表达式从左向右依次扫
描,若是操作数,则将字符转换成整数进栈;若是运算符,则连续出栈两次,第一次出栈的元素是第二个操作数,第二次出栈的元素是第一个操作数,根据当前的运算符做相应的运算,并将计算结果进栈,直到遇到’#'为止。此时栈中只剩下一个元素,即最后的运算结果,出栈即可。
#include <iostream>
using namespace std;
//后缀表达式求值(仅仅适用于个位数)
void suffix_value(char a[])
{
int i=0,x1,x2;
char s[maxSize];
int top=-1;
while(a[i]!='#')
{
switch(a[i])
{
case'+':x2=pop(s); x1=pop(s); push(s,x1+x2);break;
case'-':x2=pop(s); x1=pop(s); push(s,x1-x2);break;
case'*':x2=pop(s); x1=pop(s); push(s,x1*x2);break;
case'/':x2=pop(s); x1=pop(s);
if(x2!=0) push(s,x1/x2);
else
{
cout<<"分母为0"<<endl;
return ;
}
break;
default: push(s,a[i]-'0');//将字符转换为数字
}
i++; //处理下一个a[i]
}
cout<<"结果为"<<pop(s)<<endl;
}
//将中缀表达式转换为后缀表达式
//判断字符优先级
int prior(char a)
{
if(a=='*' || a=='/') return 4;
else if(a=='+' || a=='-') return 3;
else if(a== '(') return 2;
else if(a=='#') return 1;
else return 0;
}
//转换函数
void transform(char a[],char suff[]) //a指向算术表达式,suff存储后缀表达式
{
int i=0,k=0,n;
char ch;
Stack s;
push(s,'#');
n=strlen(a);
a[n]='#';a[n+1]='\0';
while(a[i]!='\0')
{
if(a[i]>='0' && a[i]<='9')//操作数,直接存入后缀表达式
suff[k++]=a[i];
else
switch(a[i])
{
case'(':push(s,a[i]);break;
case')':
ch=pop(s);
while(ch!='(')
{
suff[k++]=ch;
ch=pop(s);
}
break;
default:
ch=gettop(s);
while(prior(ch)>=prior(a[i]))
{
suff[k++]=ch;
ch=pop(s);
ch=gettop(s);
}
if(a[i]!='#') push(s,a[i]);
}
i++;
}
suff[k]='\0';
}
/*
(代码层面)将计算后缀表达式的函数和将中缀表达式转换为后缀表达式的函数结合
即可计算出中缀表达式的值
(手工求值层面)看参考书
*/
/*
以上算法仅适用于操作数是个位数。如果对任意的实数都能计算,需要解决如下
问题:
(1)后缀表达式中的操作数与操作数之间用空格隔开;
(2)操作数栈的元素类型为实数;
(3)将一个数字串转换为一个实数的算法;
(4)操作数为负数的情况。.
例如,原表达式为: -3+(-15. 7+9) *4. 25+7/8.2
(1)处理负数的情况
原则:第1个字符为'-',前面加0;'('之后是'-',在'('之后加0。
原表达式变为: 0-3+(0-15. 7+9) *4. 25+7/8.2
(2)在操作数与操作数之间加空格
后缀表达式为: 03- 0 15.7 -9 + 4.25 *+7 8.2/+
请读者将上述的有关算法进行修改,使其可以计算任意实数的算术表达式。
*/
int main()
{
return 0;
}
三、树和二叉树
3.1 二叉树的类型描述
typedef struct BTNode
{
char data;
struct BTNode *lchild;
struct BTNode *rchild;
}BTNode;
3.2 二叉树的创建
#include <iostream>
using namespace std;
typedef struct BTNode
{
char data;
struct BTNode *lchild;
struct BTNode *rchild;
}BTNode;
/*
以“根 左子树 右子树”的字符串形式读人结点值
的递归算法按先序遍历顺序(空结点以#表示)读人每个结点值建立二叉链表。
*/
void crt_tree(BTNode *T)//递归创建(先序遍历)
{
char c;
cin>>c;
if(ch=='#') T=NULL;
else
{
T=(BTNode*)malloc(sizeof(BTNode));
T->data=ch;
crt_tree(&T->lchild);
crt_tree(&T->rchild);
}
}
// 层次遍历可以实现非递归创建 详见p183
void Creat_BiTree(BTNode *T)
{
Queue q;
T=NULL;
char fa,ch,lrflag;//fa为父亲节点
cin>>fa>>ch>>lrflag;
while(ch!='#')
{
BTNode *p=(BTNode*)malloc(sizeof(BTNode));
p->data=ch;
p->lchild=p->rchild=NULL;
EnQueue(Q,p);
if(fa=='#') T=p; //根节点
else
{
BTNode *s=GetHead(Q);
while(s->data!=fa)//寻找当前节点的父亲节点(该过程中遇到的非父亲节点一定已经创建完成)
{
DeQueue(Q,p);
s=GetHead(Q);
}
if(lrflag==0) s->lchild=p;
else s->rchild=p;
}
cin>>fa>>ch>>lrflag;
}
}
3.3 二叉树的递归遍历(以先序遍历为例)
void preorder(BTNode *p)
{
if(p!=NULL)
{
cout<<p->data<<endl;
preorder(p->lchild);
preorder(p->rchild);
}
}
3.4 二叉树的非递归遍历
// 非递归先序遍历
void preorderNO(BTNode *bt)
{
if(bt!=NULL)
{
BTNode *stack[maxSize];
int top=-1;
// 根节点入栈
top++;
stack[top] = bt;
//开始遍历
BTNode *p;
while(top!=-1)
{
p=stack[top--];
cout<<p->data<<endl; //先序遍历(先右孩子进栈,然后是左孩子)
if(p->rchild != NULL)
{
stack[++top] = p->rchild;
}
if(p->lchild != NULL)
{
stack[++top] = p->lchild;
}
}
}
}
// 非递归中序遍历
void inorderNo(BTNode *bt)
{
if(bt!=NULL)
{
BTNode *stack[maxSize];
int top=-1;
BTNode *p;
p=bt;
while(top!=-1 || p!=NULL)
{
while(p!=NULL) //左孩子不断入栈 ,直到最左边的结点
{
stack[++top] = p;
p= p->lchild;
}
if(top!=-1)
{
p=stack[top--];
cout<<p->data<<endl;
p=p->rchild; //后访问右孩子(最左边结点是没有右孩子的,这一步会赋值为NULL,然后退回到最近的根节点进行访问,然后再对其右子树进行同样的操作)
}
}
}
}
// 非递归后序遍历
void postorder(BTNode *bt)
{
if(bt!=NULL)
{
BTNode *stack1[maxSzie]; int top1=-1;
BTNode *stack2[maxSize]; int top2=-1;
BTNode *p;
stack1[++top1]=bt;
while(top1!=-1)
{
p = stack1[top1--];
stack2[++top2] = p; // 出一个进一个,实现逆序
if(p->lchild!=NULL)
{
stack1[++top1] = p->lchild;
}
if(p->rchild!=NULL)
{
stack1[++top] = p->rchild;
}
}
while(top2!=-1)
{
p = stack2[top2--];
cout<<p->data<<endl;
}
}
}
3.5 二叉树的层次遍历
// 层次遍历
void level(BTNode *p)
{
int front,rear;
BTNode *que[15];
front=rear=0;
BTNode *q;
if(p!=NULL)
{
rear = (rear+1) % maxSize;
que[rear] = p;
while(front!=rear)
{
//出队
front = (front+1)%maxSize;
q = que[front];
cout<<q->data<<endl;
if(q->lchild != NULL)
{
rear = (rear+1) % maxSize;
que[rear] = q->lchild;
}
if(q->rchild != NULL)
{
rear = (rear+1) % maxSize;
que[rear] = q->rchild;
}
}
}
}
3.6 树的创建
- 孩子链表表示法(邻接表)
/*--------孩子链表表示法(邻接表)---------*/
typedef struct CTNode //表节点
{
int child;
struct CTNode *next;
}CTNode;
typedef struct CTbox //表头节点
{
char data;
CTNode *first;
}CTbox;
typedef struct
{
CTbox nodes[maxSize];
int n,r;//节点数目和根节点的位置
}ChildList;
void createPtree(ChildList *T)
{
int i,j,k;
CTNode *p,*s;
char father,child;
cout<<"请输入结点数"<<endl;
cin>>T->n;
getchar();
cout<<"请按照层次依次输入"<<T->n<<"个结点的值"<<endl;
for(i=0;i<T->n;i++)
{
cin>>T->nodes[i].data;
T->nodes[i].first=NULL;
}
getchar();
cout<<"请按照格式(双亲,孩子)输入"<<T->n-1<<"分支(按照层次)"<<endl;
for(i=1;i<=T->n-1;i++)
{
cin>>father>>child;
getchar();
for(j=0;j<T->n;j++) //找到父节点的值
{
if(father==T->nodes[j].data);
break;
}
if(j>=T->n)
{
cout<<"error"<<endl;
return ;
}
for(k=0;k<T->n-1;k++)//找孩子节点的值
{
if(child==T->nodes[j].data)
break;
}
if(k>=T->n)
{
cout<<"error"<<endl;
return ;
}
p=T->nodes[j].first;
if(p==NULL)//第一个孩子结点
{
s=(CTNode*)malloc(sizeof(CTNode));
s->child=k;
s->next=NULL;
T->nodes[j].first=s;
}
else //不是第一个孩子
{
while(p->next) p=p->next;
s=(CTNode*)malloc(sizeof(CTNode));
s->child=k;
s->next=NULL;
p->next=s;
}
}
}
- 孩子兄弟链表表示法
/*--------孩子兄弟链表表示法---------*/
typedef struct CSNode
{
char data;
struct CSNode *fch,*nsib;//第一个孩子和下一个兄弟
}CSNode;
void createCSTree(CSNode *T)
{
Queue q;//队列(伪代码形式)
CSNode *p,*s,*r;
T=NULL;
char fa,ch;
cin>>fa>>ch;
while(ch!='#')
{
p=(CSNode*)malloc(sizeof(CSNode));
p->data=ch;
p->fch=p->nsib=NULL;
EnQueue(q,p); //指针入队列
if(fa=='#')
T=p; //建立根节点
else
{
s=getHead(Q);
while(s->data!=fa) //在队列中找到双亲节点
{
DeQueue(Q);
s=getHead(Q);
}
if(s->fch==NULL)//第一个孩子节点
{
s->fch=p;
r=p;
}
else //不是第一个孩子
{
r->nsib=p;
r=p;
}
}
cin>>fa>>ch;
}
}
3.7 树的查找算法
/*--------树的查找算法---------*/
void preSearch(CSNode *T,char val[],CSNode *p)
{
if(T)
{
if(strcmp(val,T->data)==0)//查找成功
{
p=T;
return ;
}
preSearch(T->fch,val,p);
preSearch(T->nsib,val,p);
}
}
3.8 树的插入算法
/*--------树的结点插入---------*/
int insert(CSNode *T,char fa[],char ch[])
{
CSNode *s,*p=NULL,*q;
//fa是双亲,ch是孩子
preSearch(T,fa,&p); //查找双亲节点
if(p)
{
s=(CSNode*)malloc(sizeof(CSNode));
strcpy(s->data,ch);
s->fch=s->nsib=NULL;
if(p->fch==NULL)
p->fch=s;//第一个孩子结点
else
{
q=p->fch;
while(q->nsib) q=q->nsib;
q->nsib=s;
}
return 1;
}
return 0;
}
3.9 树的删除算法
删除树中的一个结点,约定删除以该结点为根的子树。首先根据双亲和孩子的值在孩子,兄弟链表中分别进行查找,如果有一个不存在,不能进行删除操作;否则得到双亲结点和孩子结点的地址。如果删除的结点是双亲结点的第一个孩子,重新链接其他的孩子结点,再删除第一个孩子子树;如果删除的结点不是第一个孩子,继续寻找该结点的前一个兄弟,将该结点的其他兄弟与前一个兄弟链接,再刪除以该结点为根的子树。
/*
其中函数deleteRoot()是完成子树的删除,并重接其他子树;函数postDelTree()是按照
后序遍历的顺序释放每一个结点的空间。
*/
void deleteRoot(CSNode *p,CSNode *f) //从树中删除一结点p为根的子树 ,f是p在存储结构上的双亲节点
{
if(f->fch==p) //p是f的第一个孩子,是双亲关系
{
f->fch=p->nsib;
p->nsib=NULL;
postDelTree(p);
}
if(f->nsib==p) //p与f是兄弟关系
{
f->nsib=p->nsib;
p->nsib=NULL;
postDelTree(p);
}
}
void postDelTree(CSNode *T)
{
if(T)
{
postDelTree(T->fch);
postDelTree(T->nsib);
free(T);
}
}
void deleteTree(CSNode *T,char fa[],char ch[])
{
CSNode *pfa=NULL,*pch=NULL;
if(strcmP(fa,"#")==0) //删除的是整棵树
{
postDelTree(T);
T=NULL;
return;
}
else
{
preSearch(T,fa,&pfa); //查找双亲
preSearch(T,ch,&pch); //查找孩子
if(pfa==NULL || pch=NULL)
{
cout<<"error"<<endl;
return;
}
else
{
if(pfa->fch != pch)
{
pfa=pfa->fch;
while(pfa)
{
if(pfa->nsib == pch) break;
pfa=pfa->nsib;
}
}
deleteRoot(pch,pfa);
}
}
}
3.10 树的深度
在树的孩子兄弟链表中,每棵子树根与它的左子树根是双亲与孩子的关系,每棵子树根与它的右子树根是兄弟关系,所以每棵子树的高度是(左子树高度+1)和右子树高度的最大值。
int depth(CSNode *T)
{
int d1,d2;
if(T==NULL) return 0;
d1=depth(T->fch);
d2=depth(T->nsib);
return d1+1>d2 ? d1+2:d2;
}
3.11 输出树中的所有叶子节点路径
输出树中所有从根到叶子的路径的主要步骤:
(1)树不空,将根结点进栈。
(2)如果栈顶元素的第一棵孩子树为空,路径找到,输出栈内的所有结点,转向(3);
否则继续寻找第一棵子树上的叶子路径。
(3)栈顶元素出栈。如果栈顶元素有其余的兄弟子树,回到(1)继续寻找其余的兄弟
子树上的叶子路径。
void AllTreePath(CSNode *T,Stack *s)
{
//非递归形式(可以更改为递归形式,可参考二叉树的叶子节点求法)
while(T)
{
Push(S,T->data);
if(T->fch==NULL) PrintStack(S);//只把数据打印一遍,不出栈
else
AllTreePath(T->fch,S);
Pop(s);//出栈
T=T->nsib;
}
}
3.12 二叉树的应用
3.12.1 输出二叉树的叶子节点路径
#include <iostream>
using namespace std;
#define maxSize 1500
typedef struct BTNode
{
char data;
struct BTNode *lchild;
struct BTNode *rchild;
}BTNode;
/*--------输出二叉树中所有叶子节点的路径---------*/
void AllTreePath(BTNode *T,Stack *s)
{
if(T)
{
Push(S,T->data);
if(T->lchild==NULL && T->rchild==NULL)
PrintStack(S);//只打印数据,不出栈
else
{
AllTreePath(T->lchild,S);
AllTreePath(T->rchild,S);
}
Pop(s);//出栈
}
}
3.12.2 表达式二叉树
#include <iostream>
using namespace std;
//类型描述
typedef struct BTNode
{
char data;
struct BTNode *lchild;
struct BTNode *rchild;
}BTNode; //二叉树节点
int isOperator(char ch){}//判断是否为运算符(暂时未写)
//判断字符优先级
int prior(char a)
{
if(a=='*' || a=='/') return 4;
else if(a=='+' || a=='-') return 3;
else if(a== '(') return 2;
else if(a=='#') return 1;
else return 0;
}
//创建子节点并入子树栈
void CrtNode(BTNode subTreeStack[],int &top,char ch)//subTreeStack是存储子树的栈
{
BTNode *T;
T=(BTNode*)malloc(sizeof(BTNode));
T->data=ch;
T->lchild=T->rchild=NULL;
subTreeStack[++top]=T;
}
//创建子树并入子树栈
void CrtSubTree(BTNode subTreeStack[],int &top,char c)
{
BTNode *T;
BTNode lc,rc;//一次性出栈两个元素,一个左孩子,一个右孩子
T=(BTNode*)malloc(sizeof(BTNode));
T->data=c;
lc=subTreeStack[top--];
rc=subTreeStack[top--];
T->lchild=lc;
T->rchild=rc;
subTreeStack[++top]=T;//新生成的子树的根节点入栈
}
//核心函数,创建表达式二叉树
void CrtExptree(BTNode *T,char exp[])
{
BTNode subTreeStack[maxSize];int subTreeTop=-1;//子树栈
BTNode charStack[maxSize];int charStackTop=-1;//运算符栈
charStack[++top]='#';//结束符入栈
char ch,c;
int i=0;
while( (c=charStack[top])!='#' || exp[i]!='#' )
{
if(!isOperator(exp[i]))
CrtNode(subTreeStack,subTreeTop,exp[i]);//非运算符,直接建立叶节点并入子树栈中
else
{
switch(exp[i])
{
case'(':charStack[++charStackTop]=exp[i];break;//左括号
case')':c=charStack[charStackTop--];//右括号
while(c!='(')
{
CrtSubTree(subTreeStack,c);
c=charStack[charStackTop--];
}
default:
while( (c=charStack[charStackTop])!='#' && prior(c)>prior(exp[i]))
{
/*
当栈顶运算符不是#号且优先级高于表达式中的当
前运算符,则取栈顶的运算符建子树,再出栈
*/
CrtSubTree(subTreeStack,subTreeTop,c);
charStackTop--;//出栈
}
if(exp[i]!='#')
charStack[++charStackTop]=exp[i];
}
}
if(exp[i]!='#') i++;
}
T=subTreeStack[top--];//二叉树根节点出栈
}
/*
表达式二叉树的计算(使用后序遍历)
*/
double culExp(BTNode *T)
{
double result,a,b;
if(T)
{
if(!isOperator(T->data))//如果不是运算符,说明是字母变量,需要输入具体值,同时也是叶子节点
{
cout<<"请输入变量"<<T->data<<"的值"<<endl;
cin>>result;
return result;
}
a=culExp(T->lchild);
b=culExp(T->rchild);
//后序遍历进行计算
switch(T->data)
{
case'+':return a+b;
case'-':return a-b;
case'*':return a*b;
case'/':
if(b!=0)
return a/b;
else
{
cout<<"分母为0";
exit(0);
}
}
}
}
int main()
{
return 0;
}
四、图
4.1 图的创建
4.1.1 邻接矩阵创建
/***********邻接矩阵***********/
typedef struct
{
int edges[maxSize][maxSize];
int n,e;
}MGraph;
/*邻接矩阵创建(以无向图为例)*/
void crt_graph(MGraph *G)
{
cin>>G->n>>G->e;//输入顶点数和边数
/*初始化*/
for(int i=0;i<G->n;i++)
for(int j=0;j<G->n;j++)
G->edges[i][j]=0;
for(int k=0;k<G->e;k++)
{
int i,j;
cin>>i>>j;
G->edges[i][j]=G->edges[j][i]=1;
}
}
4.1.2 邻接表创建
/***********邻接表存储法***********/
// 被指向的点
typedef struct ARCNode
{
int vex;
struct ARCNode *next;
char info;
}ARCNode;
// 顶点
typedef struct VNode
{
int data;
ARCNode *first;
}VNode;
//邻接表
typedef struct
{
VNode list[maxSize];
int n,e;
}AGraph;
//邻接表创建(以有向图为例)
void build_list(AGraph *G)
{
cin>>G->n>>G->e;//顶点数和边数
for(int i=0;i<G->n;i++)
{
// 创建表节点(以编号形式输入)
cin>>G->list[i].data;
G->list[i].first=NULL;
}
for(int k=0;k<G->e;k++)//创建边
{
int i,j;
cin>>i>>j;
ARCNode *p=(ARCNode*)malloc(sizeof(ARCNode));
p->vex=j;//假设编号和下标一致
//头插法插入
p->next=G->list[i].first;
G->list[i].first=p;
}
}
4.2 图的遍历
#include <iostream>
#include<malloc.h>
using namespace std;
#define maxSize 150
int visit[maxSize];
/***********邻接表存储法***********/
// 被指向的点
typedef struct ARCNode
{
int vex;
struct ARCNode *next;
char info;
}ARCNode;
// 顶点
typedef struct VNode
{
char data;
ARCNode *first;
}VNode;
//邻接表
typedef struct
{
VNode list[maxSize];
int n,e;
}AGraph;
//------- 深度优先遍历----------//
void DFS(AGraph *G,int v)
{
ARCNode *p;
visit[v]=1;
cout<<G->list[v].data<<" ";
p=G->list[v].first;
while(p!=NULL)
{
if(visit[p->vex]==0)
DFS(G,p->vex);
p=p->next;
}
}
/*广度优先遍历*/
void BFS(AGraph *G,int v)
{
ARCNode *p;
int que[maxSize];int front=0,rear=0;
int j;
cout<<G->list[v].data<<endl;
visit[v]=1;
rear=(rear+1)%maxSize;
que[rear]=1;
while(front!=rear)
{
front=(front+1)%maxSize;
int j = que[front];
p=G->list[j].first;
while(p!=NULL)
{
if(visit[p->vex]==0)
{
cout<<G->list[p->vex].data<<endl; //先访问,后入队
visit[p->vex]=1;
rear=(rear+1)%maxSize;
que[rear]=p->vex;
}
p=p->next
}
}
}
int main()
{
return 0;
}
4.3 最小生成树
4.3.1 Prim算法
//邻接矩阵
typedef struct
{
int edges[maxSize][maxSize];
int n,e;
}MGraph;
void Prim(MGraph g,int v0,int &sum)
{
int lowcost[maxSize],vset[maxSize],v;
int i,j,k,min;
v=v0;
//初始化
for(i=0;i<g.n;i++)
{
lowcost[i]=g.edges[v0][i];
vset[i]=0;
}
vset[v0]=1;
sum=0;
for(i=0;i<g.n-1;i++)
{
min=INF;
//选择距离最小者(在lowcost数组中选取)
for(j=0;j<g.n;j++)
{
if(vset[j]==0 && lowcost[j]<min)
{
min=lowcost[j];
k=j;
}
}
// 并入
vset[k]=1;
v=k;//准备更新信息,k为这次的跳板
sum+=min; //error 出错点
for(j=0;j<g.n;j++)
{
if(vset[j]==0 && g.edges[v][j]<lowcost[j])
{
lowcost[j]=g.edges[v][j];
}
}
}
}
4.3.2 Kruskal算法
/*-------克鲁斯卡尔-------*/
typedef struct
{
int a,b;
int w;
}Road;
Road road[maxSize]; // 路径信息
int v[maxSize]; //并查集使用
//获取根节点
int getRoot(int a)
{
while(a!=v[a]) a=v[a];
return a;
}
void Kruskal(MGraph g,int &sum,Road road[])
{
//初始化
int i;
int N,E,a,b;
N=g.n;
E=g.e;
sum=0;
for(i=0;i<N;i++)
{
v[i]=i;
}
sort(road,E);//按照边的长度进行排序
for(i=0;i<E;i++)
{
a=getRoot(road[i].a);
b=getRoot(road[i].b);
if(a!=b)
{
v[a]=b;
sun+=road[i].w; //error出错点
}
}
}
4.4 最短路算法
#include <iostream>
using namespace std;
#define INF 99999999
typedef struct
{
int edges[maxSize][maxSize];
int n,e;
}MGraph;
/**************Dijkstra算法********************/
void Dijkstra(MGraph g,int v,int dist[],int path[])
{
int set[maxSize];
int min,i,j,u;
for(i=0;i<g.n;++i)
{
dist[i]=g.edges[v][i];
set[i]=0;
if(g.edges[v][i]<INF)
{
path[i]=v;
}
else
path[i]=-1;
}
set[v]=1;path[v]=-1;
/*关键操作*/
for(i=0;i<g.n-1;i++)
{
min=INF;
//选取最小的点
for(j=0;j<g.n;++j)
{
u=j;
min=dist[j];
}
set[u]=1;
//更新路径
for(j=0;j<g.n;++j)
{
if(set[j]==0 && dist[j]>dist[u]+g.edges[u][j]) //忘记set为0
{
dist[j]=dist[u]+g.edges[u][j];
path[j]=u; //更新前驱
}
}
}
}
// 打印路径
void printPath(int path[],int a)
{
int stack[maxSize];int top=-1;
while(path[a]!=-1)
{
stack[++top]=a;
a=path[a];
}
stack[++top]=a;
while(top!=-1)
cout<<stack[top--]<<" ";
cout<<endl;
}
/**************Flyod算法**********/
void printpath(int u,int v,int path[][max])
{
if(A[u][v]==INF)
else
{
if(path[u][v]==-1)
cout<<u<<"--->"<<v;
else
{
int mid=path[u][v];
printpath(u,mid,path);
printpath(mid,v,path);
}
}
}
void Flyod(MGraph *g,int path[][maxSize],int A[][maxSize])
{
int i,j,k;
for(i=0;i<g->n;i++)
for(j=0;j<g->n;j++)
{
A[i][j]=g->edges[i][j];
path[i][j]=-1;
}
for(k=0;k<g->n;++k)
for(i=0;i<g->n;i++)
for(j=0;j<g->n;j++)
{
if(A[i][j]>A[i][k]+A[k][j])
{
A[i][j]=A[i][k]+A[k][j];
path[i][j]=k;
}
}
}
int main()
{
return 0;
}
五、查找
4.1 顺序查找(带哨岗)
#include <iostream>
using namespace std;
int SeqSearch(int A,int k,int len)
{
A[0]=k;//存放岗哨
for(int i=len;A[i]!=k;i--);
return i;//如i为0,说明查找失败
}
int main()
{
return 0;
}
4.2 折半查找
#include <iostream>
using namespace std;
int Bsearch(int R[],int low,int high,int k)
{
int mid;
while(low<=high)
{
mid=(low+high)/2;
if(R[mid]==k)
return mid;
else if(R[mid]>k)
high=mid-1;
else
low=mid+1;
}
return -1; //查找失败则返回-1
}
int main()
{
int R[150];
int n;
cin>>n;
for(int i=0;i<n;i++)
cin>>R[i];
int flag = Bsearch(R,0,n-1,5);
cout<<R[flag]<<endl;
return 0;
}
4.3 二叉排序树
#include <iostream>
using namespace std;
typedef struct BTNode
{
int key;
struct BTNode *lchild;
struct BTNode *rchild;
}BTNode;
/**
* 查找关键字
*/
BTNode* BSTSearch(BTNode *bt,int key)
{
if(bt==NULL)
return NULL;
else
{
if(bt->key==key)
return bt;
else if(key<bt->key)
return BSTSearch(bt->lchild,key); //小于根节点,到左子树查找
else
return BSTSearch(bt->rchild,key); //查找右子树
}
}
/**
* 插入关键字
**/
BTNode *(BTNode *&bt,int key)
{
if(bt==NULL)
{
bt=(BTNode*)malloc(sizeof(BTNode));
bt->lchild=bt->rchild=NULL;
bt->key=key;
return 1;
}
else
{
if(bt->key==key)
return 0;
else if(key<bt->key)
return BSTInsert(bt->lchild,key);
else
return BSTInsert(bt->rchild,key);
}
}
/**
* 构造二叉排序树
**/
void CreatBST(BTNode *&bt,int key[],int n)
{
int i;
bt=NULL;
for(i=0;i<n;i++)
BSTInsert(bt,key[i]);
}
int main()
{
return 0;
}
六、排序
6.1 直接插入排序
#include <iostream>
using namespace std;
void InsertSort(int R[],int n)
{
int i,j;
int temp;
for(i=1;i<n;i++) //i从1开始
{
temp=R[i];
j=i-1; //key
while(j>=0 && temp<R[j])
{
R[j+1]=R[j]; //向后移动
--j;
}
R[j+1]=temp;
}
}
int main()
{
int R[15];
int n;
cin>>n;
for(int i=0;i<n;i++)
{
cin>>R[i];
}
InsertSort(R,n);
for(int i=0;i<n;i++)
{
cout<<R[i]<<" ";
}
return 0;
}
6.2 折半插入排序
#include <iostream>
using namespace std;
void BinsertSort(int A[],int len)
{
int i,j,m,low,high;
for(i=2;i<=len;i++)
{
A[0]=A[i];//A[i]暂时存入A[0]中
low=1;high=i-1;
while(low<=high)
{
m=(low+high)/2;
if(A[0]>R[m])
high=m-1;
else
low=m+1;
}
for(j=i-1;j>=high+1;--j)
A[j+1]=A[j];//元素后移
R[high+1]=R[0];//插入
}
}
6.3 冒泡排序
#include <iostream>
using namespace std;
void BubbleSort(int R[],int n)
{
int i,j,flag;
int temp;
for(i=n-1;i>=1;i--)
{
flag=0;
for(j=1;j<=i;j++)
{
if(R[j-1]>R[j])
{
temp=R[j];
R[j]=R[j-1];
R[j-1]=temp;
flag=1;
}
}
if(flag==0)
return;
}
}
int main()
{
int R[15];
int n;
cin>>n;
for(int i=0;i<n;i++)
{
cin>>R[i];
}
BubbleSort(R,n);
for(int i=0;i<n;i++)
cout<<R[i]<<" ";
return 0;
}
6.4 快速排序
#include <iostream>
#include<stdlib.h>
using namespace std;
int sum;
void QuickSort(int R[],int low,int high)
{
sum++;
int temp;
int i=low,j=high;
if(low<high)
{
temp=R[low]; //选出中间点
while(i<j)
{
while(j>i && R[j]>=temp) j--; //先从右往左
if(i<j)
{
R[i]=R[j];
++i; //key
}
//从左往右扫描
while(i<j && R[i]<=temp) i++;
if(i<j)
{
R[j]=R[i];
j--; //key
}
R[i]=temp;
QuickSort(R,low,i-1);
QuickSort(R,i+1,high);
}
}
}
6.5 二路归并排序
#include <iostream>
using namespace std;
#define max 100
void merge(int A[], int L1, int R1, int L2, int R2)
{
int i=L1,j=L2;
int temp[max], index=0;
while(i<=R1 && j<=R2)
{
if(A[i] <= A[j])
{
temp[index++] = A[i++];
}
else
{
temp[index++] = A[j++];
}
}
while(i <= R1) temp[index++] = A[i++];
while(j <= R2) temp[index++] = A[j++];
//将temp的值一一赋给A[L1~R2]
for(int i=0; i<index; i++)
{
A[L1+i] = temp[i];
}
}
void mergeSort(int A[],int low,int high)
{
if(low<high)
{
int mid=(low+high)/2;
mergeSort(A,low,mid); //归并前半段
mergeSort(A,mid+1,high); //归并后半段
merge(A,low,mid,mid+1,high); //将low->mid和mid+1->high两个有序序列合并成一个有序序列
}
}
int main()
{
int R[max];
for(int i=0;i<6;i++)
cin>>R[i];
mergeSort(R,0,5);
for(int i=0;i<6;i++)
cout<<R[i]<<" ";
return 0;
}