目录
2.4.如果有LNode *p,*s,若p指向其中一个节点(该节点不为空),s指向一个新的节点,要求:
1.复数的计算
定义抽象数据类型,实现复数的运算。
就是简单的模拟一下数学中复数的计算。
复数的相加
a+bi和c+di:a+c+(b+d)i;
复数的相减
a+bi和c+di:a-c+(b-d)i;
复数的相乘
a+bi和c+di:a*c-b*d+(a*d+b*c)i;
复数的相除
a+bi和c+di:(a*c+b*d+(b*c-a*d)i)/(c*c+d*d);
#include<iostream>
using namespace std;
//创建抽象函数
typedef struct{
float realpart;
float imagpart;
}complex;
//创建复数
void create(complex &C,float x,float y)
{
C.realpart=x;
C.imagpart=y;
}
//实现加法
void add(complex a,complex b,complex &c)
{
c.realpart=a.realpart+b.realpart;
c.imagpart=a.imagpart+b.imagpart;
}
//实现减法
void jian(complex a,complex b,complex &c)
{
c.realpart=a.realpart-b.realpart;
c.imagpart=a.imagpart-b.imagpart;
}
//实现乘法
void mul(complex a,complex b,complex &c)
{
c.realpart=a.realpart*b.realpart-a.imagpart*b.imagpart;
c.imagpart=a.realpart*b.imagpart+a.imagpart*b.realpart;
}
//实现除法
void chu(complex a,complex b,complex &c)
{
c.realpart=(a.realpart*b.realpart+a.imagpart*b.imagpart)/(b.realpart*b.realpart+2*b.realpart*b.imagpart+a.imagpart*a.imagpart);
c.imagpart=(a.imagpart*b.realpart-a.realpart*b.imagpart)/(b.realpart*b.realpart+2*b.realpart*b.imagpart+a.imagpart*a.imagpart);
}
//取实部
void getRealpart(complex a,float &x)
{
x=a.realpart;
}
//取虚部
void getImagpart(complex a,float &x)
{
x=a.imagpart;
}
int main()
{
while(1)
{
complex a,b,c;
float x1,x2,y1,y2;
cout<<"请输入第一个复数的实部:";
cin>>x1;
cout<<endl;
cout<<"请输入第一个复数的虚部:";
cin>>y1;
cout<<endl;
cout<<"请输入第二个复数的实部:";
cin>>x2;
cout<<endl;
cout<<"请输入第二个复数的虚部:";
cin>>y2;
cout<<endl;
create(a,x1,y1);
create(b,x2,y2);
cout<<"请你选择+、-、*、/:";
string op;
cin>>op;
if(op=="+")
add(a,b,c);
else if(op=="-")
jian(a,b,c);
else if(op=="*")
mul(a,b,c);
else if(op=="/")
chu(a,b,c);
cout<<"answer=";
if(c.imagpart>0)
cout<<c.realpart<<"+"<<c.imagpart<<"i"<<endl;
else if(c.imagpart==0)
cout<<c.realpart<<endl;
else cout<<c.realpart<<c.imagpart<<"i"<<endl;
string p;
cout<<"是否继续计算(y/n):";
cin>>p;
if(p=="n"||p=="N") break;
}
return 0;
}
2.单链表
2.1.单链表的定义。
typedef struct LNode{
int data;
struct LNode *next;
}LNode,*LinkList;
2.2.定义一个为L的单链表。
LNode *L;//或者LinkList L;
2.3.交换第k个节点,和第k+1个节点的值。
bool change(LinkList L,int k)
{
LNode *p=L;//让p指向头节点
int j=0; //计数器,帮助找到第k个节点
while(p->next!=NULL&&j<k)//遍历链表,直到找到第k个节点
{
p=p->next;
j++;
}
if(!(p->next)&&j>k) //需要保证p的后继节点存在
return false;
//交换k和k+1节点的值
int x=p->data;
p->data=p->next->data;
p->next->data=x;
return true;
}
2.4.如果有LNode *p,*s,若p指向其中一个节点(该节点不为空),s指向一个新的节点,要求:
(1).在p后面插入节点s。
s->next=p->next;
p->next=s;
(2).在p节点前插入s。
第一种方法:
遍历找到p前面的节点。
void insert()
{
LNode *q=L;
while(q->next!=p) q=q->next;
s->next=q->next;//或者s->next=p;
q->next=s;
}
时间复杂度为O(n),空间复杂度为O(1)。
第二种方法:
假设原来的序列是x,y,p指向y,需要在y前面插入一个节点s,此时顺序为x,s,y,如y后面插入节点s ,那么此时的顺序为x,y,s,我们发现只要交换y和s节点的数据域即可。
void insert()
{
//在p后面插入节点
s->next=p->next;
p->next=s;
//交换节点p和s的数据域,此时s就是p后面的一个节点
int x=p->data;
p->data=p->next->data;
p->next->data=x;
}
时间复杂度为O(1),空间复杂度为O(1)。
2.5.求单链表的长度
遍历链表即可。
int Listlength(LinkList L)
{
int j=0;
LNode *p=L;
while(p->next!=NULL)
{
j++;
p=p->next;
}
return j;
}
2.6.按下标取单链表中的某个元素。
遍历找到下标。
bool GetElem(LinkList L,int i,int &e)//因为需要把值传回去,加&
{
LNode *p=L;
int j=0;
while(p&&j<i)
{
p=p->next;
j++;
}
if(!p||j>i) return false;
e=p->data;
return true;
}
//时间复杂度O(n)
2.7.按值查找操作
该操作需要依次用单链表中的元素与所给数据进行比较。
具体方法:设置一个指针p依次指示每个节点,比较e和p所指节点的值,如果p->data==e,表示查找成功,返回该元素的地址;否则继续进行搜索,直到表尾;如果没有找到,表示查找失败,返回NULL
LNode &LocateElem(LinkList L,int e)
{
LNode *p;
p=L->next;
while(p!=NULL&&p->data!=e)
p=p->next;
if(!p) return NULL:
return p->next;
}
2.8.插入元素
//基本操作
s=new LNode;
s->data=e;
s->next=p->next;
p->next=s;
完整代码:
bool ListInsert(LinkList &L,int i,int e)//在i之前插入一个节点
{
LNode *p=L;
int j=0;
while(p&&j<i-1)//找到i-1节点
{
p=p->next;
++j;
}
if(!p||j>i-1) //参数不合法,i小于1或者大于表长+1
return false;
s=new LNode; //创建新节点
if(!s) exit(-2);//创建失败
s->data=e;
s->next=p->next;
p->next=s;
return true;
}
2.9.删除操作
假设删除第i个节点后面的节点,假设p指向第i个节点,那么之间p->next=p->next->next;
bool ListDete(LinkList &L,int i,int &e)
{
LNode *p=L;
int j=0;
while(p->next&&j<i-1)//寻找i-1个节点,并令p指向该结点
{
p=p-next;
++j;
}
if(!(p->next)||j>i-1) return false;
LNode q=p->next;
p->next=q->next;
e=q->data;
delete q; //释放空间
return true;
}
2.10.建立单链表
(1).头插法
顺序相反,如果插入顺序是x,y,z,在单链表中是z,y,x。
void GreateList(LinkList &L,int n)
{
L=(LNode *)malloc(sizeof(LNode));
L->next=NULL;
for(int i=0;i<n;i++)
{
p=new LNode;
cin>>p->data;
p->next=L->next;
L->next=p;
}
}
(2).尾插法
顺序相同。
void GreateList(LinkList &L,int n)
{
L=new LNode;
LNode r=L;
for(int i=0;i<n;i++)
{
p=new LNode;
cin>>p->data;
r->next=p;
r=p;
}
r->next=NULL;//将尾结点置空
}
2.11.实现
头插法,尾插法,插入,删除。
#include<iostream>
using namespace std;
//定义
typedef struct LNode{
int data;
struct LNode *next;
}LNode,*LinkList;
//初始化
void InitList(LinkList &L)
{
L=new LNode;
L->next=NULL;
}
//头插法
LinkList HeadInsert(LinkList &L,int n)
{
InitList(L);
for(int i=0;i<n;i++)
{
LNode *p=new LNode;
cin>>p->data;
p->next=L->next;
L->next=p;
}
return L;
}
//尾插法
LinkList TailInsert(LinkList &L,int n)
{
InitList(L);
LNode *r=L;
for(int i=0;i<n;i++)
{
int x;
cin>>x;
LNode *p=new LNode;
p->data=x;
r->next=p;
r=p;
}
r->next=NULL;
return L;
}
//插入
void InsertList(LinkList &L,int i,int e)
{
LNode *p=L;
int j=0;
while(p->next!=NULL&&j<i)
{
p=p->next;
++j;
}
LNode *s=new LNode;
s->data=e;
s->next=p->next;
p->next=s;
}
//删除
void DeleteList(LinkList &L,int i)
{
LNode *p=L;
int j=0;
while(j<i-1&&p)
{
p=p->next;
++j;
}
LNode *s=p->next;
p->next=s->next;
delete s;
}
//打印
void PrintfList(LinkList &L)
{
LNode *p=L->next;
while(p)
{
cout<<p->data<<" ";
p=p->next;
}
}
void f()
{
cout<<"1.头插法"<<endl;
cout<<"2.尾插法"<<endl;
}
int main()
{
LNode *L;
InitList(L);
cout<<"请输入长度:";
int n;
cin>>n;
f();
int op;
cin>>op;
if(op==1)
L=HeadInsert(L,n);
else if(op==2)
L=TailInsert(L,n);
int i,e;
cout<<"请输入插入位置和值:";
cin>>i>>e;
InsertList(L,i,e);
cout<<"插入后:";
PrintfList(L);
cout<<endl;
cout<<"请输入删除位置:";
int a;
cin>>a;
DeleteList(L,a);
cout<<"删除后:";
PrintfList(L);
return 0;
}
2.12.把负数放在正数前面(1)
单链表本身有一批元素(没有0),实现把负数放在正数前面,且保证原来的相对顺序保持不变。
算法思想:因为尾插法不会改变单链表当中元素的顺序,用尾插法创建单链表,遍历原来的链表,拆分到两个新的链表中,把负数和正数分别放在两个链表中,因为是尾插法,所以正负数的相对位置不会发生变化,然后重新合并两个链表。
#include<iostream>
using namespace std;
typedef struct LNode{
int data;
struct LNode *next;
}LNode,*LinkList;
//尾插法
LinkList CreateList(int size)
{
LinkList head=new LNode;
head->next=NULL;
LNode* p=head;
LNode* q=NULL;
for(int i=0;i<size;i++)
{
q=new LNode;
cin>>q->data;
q->next=NULL;
p->next=q;
p=q;
}
return head;
}
//把负数放在正数前面
void sort(LinkList L,int n)
{
LNode* L1=new LNode;L1->next=NULL;LNode* x=L1;//L1存放负数
LNode* L2=new LNode;L2->next=NULL;LNode* y=L2;//L2存放正数
LNode* p=L->next;
LNode* q=NULL;
//拆分
while(p!=NULL)
{
if(p->data<0)
{
q=new LNode;
q->data=p->data;
q->next=NULL;
x->next=q;
x=q;
}
else
{
q=new LNode;
q->data=p->data;
q->next=NULL;
y->next=q;
y=q;
}
p=p->next;
}
//合并
p=L->next;
LNode* x2=L1->next;
LNode* y2=L2->next;
for(int i=0;i<n;i++)
{
if(x2!=NULL)
{
if(p)
{
p->data=x2->data;
x2=x2->next;
p=p->next;
}
}
else
{
if(p)
{
p->data=y2->data;
y2=y2->next;
p=p->next;
}
}
}
}
//打印
void PrintfList(LNode* L)
{
LNode* p=L->next;
while(p!=NULL)
{
cout<<p->data<<" ";
p=p->next;
}
}
int main()
{
LNode* L;
int n;
cin>>n;
L=CreateList(n);
sort(L,n);
PrintfList(L);
return 0;
}
2.13.把负数放在正数前面(2)
用一个辅助链表。
void sort(LinkList L,int n)
{
LNode* p=L->next;
LNode* R=new LNode;R->next=NULL;LNode *x=R;
LNode* q=NULL;
//拆分,先将负数插入R中。
while(p)
{
if(p->data<0)
{
q=new LNode;
q->data=p->data;
x->next=q;
x=q;
}
p=p->next;
}
//再插入正数
p=L->next;
while(p)
{
if(p->data>0)
{
q=new LNode;
q->data=p->data;
x->next=q;
x=q;
}
}
//合并
p=L->next;
LNode* m=R-next;
for(int i=0;i<n;i++)
{
if(m!=NULL)
{
if(p)
{
p->data=m->data;
m=m->next;
p=p->next;
}
}
}
}
2.14.找单链表数据域最大值
方法:比较交换法。
int max(LinkList &L)
{
if(L->next=NULL) return NULL;
int m=L->next->data;
LNode* p=L->next->next;
while(p)
{
if(p->data>m) m=p->data;
p=p->next;
}
return m;
}
时间复杂度O(n),空间复杂度O(1)。
2.15.合并两个有序单链表
以归并排序思想合并两个有序单链表。
样例输入
4 4
1 2 5 7
3 5 7 8
样例输出
1 2 3 5 5 7 7 8
LinkList sort(LinkList &L,LinkList &R)
{
if(L->next==NULL||R->next==NULL) return NULL;
LNode* m=L->next;
LNode* n=R->next;
LNode* C=new LNode;C->next=NULL;LNode* x=c;
LNode* q=NULL;
//归并的过程
while(m&&n)
{
if(m->data<n->data)
{
q=new LNode;
q=data=m->data;
x->next=q;
x=q;
m=m->next;
}
else
{
q=new LNode;
q->data=n->data;
x->next=q;
x=q;
n=n->next;
}
}
//扫尾
while(m)
{
q=new LNode;
q->data=m->data;
x->next=q;
x=q;
m=m->next;
}
while(n)
{
q=new LNode;
q->data=n->data;
x->next=q;
x=q;
n=n->next;
}
return C;
}
完整代码
#include<iostream>
using namespace std;
typedef struct LNode{
int data;
struct LNode *next;
}LNode,*LinkList;
//尾插法
LinkList create(int size)
{
LinkList head=new LNode;
head->next=NULL;
LNode* p=head;
LNode* q=NULL;
for(int i=0;i<size;i++)
{
q=new LNode;
cin>>q->data;
q->next=NULL;
p->next=q;
p=q;
}
return head;
}
//归并思想合并
LinkList sort(LinkList &L,LinkList &R)
{
if(L->next==NULL||R->next==NULL) return NULL;
LNode* m=L->next;
LNode* n=R->next;
LNode* C=new LNode;C->next=NULL;LNode* x=C;
LNode* q=NULL;
while(m&&n)
{
if(m->data<n->data)
{
q=new LNode;
q->data=m->data;
x->next=q;
x=q;
m=m->next;
}
else
{
q=new LNode;
q->data=n->data;
x->next=q;
x=q;
n=n->next;
}
}
while(m)
{
q=new LNode;
q->data=m->data;
x->next=q;
x=q;
m=m->next;
}
while(n)
{
q=new LNode;
q->data=n->data;
x->next=q;
x=q;
n=n->next;
}
return C;
}
//打印
void print(LNode* L)
{
LNode* p=L->next;
while(p!=NULL)
{
cout<<p->data<<" ";
p=p->next;
}
}
int main()
{
LNode* L;
LNode* R;
int n,m;
cin>>n>>m;
L=create(n);
R=create(m);
print(sort(L,R));
return 0;
}
2.16.单链表去重
void f(LNode* head)
{
LNode* p=head;
LNode* q;
for(p=head->next;p;p=p->next)
{
LNode* pre=p;
for(q=p->next;q;q=q->next)
{
if(p->data==q->data) pre->next=q->next;
else pre=q;
}
}
}
2.17.单链表逆置
方法:遍历单链表,用头插法的方法实现逆置。
void InverseList(LinkList &L)
{
LNode* p=L->next;
L->next=NULL;
LNode* q=NULL;
while(p)
{
q=p->next;
p->next=L->next;
L->next=p;
p=q;
}
}
时间复杂度O(n),空间复杂度O(1).
2.18.单链表(删除大于mink小于maxk的结点)
算法思想:先找到临界值,然后进行删除。
样例输入
10
1 2 3 4 5 6 7 8 9 10
5 9
样例输出
1 2 3 4 5 9 10
#include<iostream>
using namespace std;
typedef struct LNode{
int data;
struct LNode *next;
}LNode,*LinkList;
//尾插法
LinkList create(int size)
{
LinkList head=new LNode;
head->next=NULL;
LNode* p=head;
LNode* q=NULL;
for(int i=0;i<size;i++)
{
q=new LNode;
cin>>q->data;
q->next=NULL;
p->next=q;
p=q;
}
return head;
}
//遍历
void print(LNode* L)
{
LNode* p=L->next;
while(p!=NULL)
{
cout<<p->data<<" ";
p=p->next;
}
}
//删除
void DeleteList(LinkList &L,int mink,int maxk)
{
LNode* p=L->next;
LNode* pre;
LNode* q;
while(p->data<=mink)
{
pre=p;
p=p->next;
}
if(p)
{
while(p&&p->data<maxk)
p=p->next;
q=pre->next;
pre->next=p;
while(q!=p)
{
LNode* s=q->next;
delete q;
q=s;
}
}
}
int main()
{
LNode* L;
int n;
cin>>n;
L=create(n);
int mink,maxk;
cin>>mink>>maxk;
DeleteList(L,mink,maxk);
print(L);
return 0;
}
2.19.单链表按值删除
题目描述
构造一个单链表,删除值为x的元素。
#include<iostream>
using namespace std;
typedef struct LNode{
int data;
struct LNode *next;
}LNode,*LinkList;
LinkList create(int size)
{
LinkList head=new LNode;
head->next=NULL;
LNode* p=head;
LNode* q=NULL;
for(int i=0;i<size;i++)
{
q=new LNode;
cin>>q->data;
q->next=NULL;
p->next=q;
p=q;
}
return head;
}
void print(LinkList L)
{
LNode* p=L->next;
while(p!=NULL)
{
cout<<p->data<<" ";
p=p->next;
}
}
void DeleteList(LinkList &L,int m)
{
LNode* p=L->next;
LNode* pre=L;
LNode* q;
while(p!=NULL)
{
if(p->data==m)
{
q=p;
p=p->next;
pre->next=p;
delete q;
}
else
{
pre=p;
p=p->next;
}
}
}
int main()
{
LNode* L;
int n;
cin>>n;
int m;
cin>>m;
DeleteList(L,m);
print(L);
return 0;
}
2.20.经典问题
题目描述
将一批单链表(a1,a2,...,am,b1,b2,...,bn)变成(b1,b2,..,bn,a1,a2,...,am).
1.算法思想:开一个辅助链表,先找到原链表L中的下标为m+1的结点,把m+1之后的结点都插入新链表R中,然后再把1~m的结点插入R中 ,然后把R中的结点归还给L。
样例输入
5
1 2 3 4 5
3
样例输出
4 5 1 2 3
2.完整代码:
#include<iostream>
using namespace std;
typedef struct LNode
{
int data;
struct LNode *next;
}LNode,*LinkList;
//尾插法
LinkList create(int size)
{
LinkList head=new LNode;
head->next=NULL;
LNode* p=head;
LNode* q=NULL;
for(int i=0;i<size;i++)
{
q=new LNode;
cin>>q->data;
q->next=NULL;
p->next=q;
p->next=q;
p=q;
}
return head;
}
void print(LinkList &L)
{
LNode* p=L->next;
while(p!=NULL)
{
cout<<p->data<<" ";
p=p->next;
}
}
void f(LinkList &L,int m,int n)
{
LNode* p=L->next;
LNode* R=new LNode;R->next=NULL;LNode* x=R;
LNode* q=NULL;
for(int i=0;i<m;i++)
p=p->next;
while(p!=NULL)
{
q=new LNode;
q->data=p->data;
x->next=q;
x=q;
p=p->next;
}
p=L->next;
for(int i=0;i<m;i++)
{
q=new LNode;
q->data=p->data;
x->next=q;
x=q;
p=p->next;
}
//归还
p=L->next;
x=R->next;
for(int i=0;i<n;i++)
{
p->data=x->data;
x=x->next;
p=p->next;
}
}
int main()
{
LNode* L;
int n,m;
cin>>n;
L=create(n);
cin>>m;
f(L,m,n);
print(L);
return 0;
}
3.时间复杂度O(n),空间复杂度O(n);
2.21.找有序单链表中的中位数
题目描述
找出有序链表中的中位数,如果是偶数个数,取中间两个数的平均数,结果自动保留两位小数。
样例输入1:
1 2 3 4 5
3.00
样例输入2:
1 2 3 4
2.50
class Solution{
public:
double fun(struct LNode* L,int n)
{
LNode* p=L->next;
if(n%2!=0)
{
for(int i=1;i<n/2+1;i++)
p=p->next;
return p->data;
}
else
{
for(int i=1;i<=n/2-1;i++)
p=p->next;
return (1.0)*(p->data+p->next->data)/2;
}
}
};
2.22.从尾到头打印单链表
题目描述
从尾到头打印单链表。
样例输入
[1,2,3,4,5]
样例输出
5 4 3 2 1
class Solution{
public:
vector<int> printf(LNode* L)
{
vector<int> res;
LNode* p=L->next;
while(p)
{
res.push_back(p->data);
p=p->next;
}
return vector<int>(res.rbegin(),res.rend());
}
};
3.单循环链表
3.1.单循环链表的定义
typedef struct Node{
int data;
struct Node *next;
}Node,*LinkList;
3.2.初始化
void InitList(LinkList &L)
{
L=new Node;
L->next=L;
}
3.3.头插法建表
void GreateList(LinkList &L,int n)
{
L=(Node *)malloc(sizeof(Node));
L->next=L;
for(int i=0;i<n;i++)
{
p=new Node;
cin>>p->data;
p->next=L->next;
L->next=p;
}
}
3.4.尾插法
void CreateList(LinkList &L,int n)
{
L=new Node;
Node r=L;
for(int i=0;i<n;i++)
{
p=new Node;
cin>>p-data;
r->next=p;
r=p;
}
r->next=L;
}
3.5.求链表长度
int Listlength(LinkList L)
{
int j=0;
Node *p=L;
while(p->next!=L)
{
j++;
p=p->next;
}
return j;
}
4.顺序栈的基本操作
一些基本操作:给定n组,每组一个正整数op,op规定如下:
op==1时,定义正数x入栈。
op==2时,出栈。
op==3时,取栈顶元素。
#include<iostream>
#define MAXSIZE 5
using namespace std;
typedef struct
{
int *base;
int *top;
int stacksize;
}SqStack;
//初始化
bool InitStack(SqStack &S)
{
S.base=new int[MAXSIZE];//给栈顶分配存储空间
if(!S.base) return false;
S.top=S.base;
S.stacksize=MAXSIZE;
return true;
}
//入栈
bool Push(SqStack &S,int &e)
{
if(S.top-S.base==S.stacksize)
return false;
*S.top=e;
*S.top++;
return true;
}
//出栈
bool Pop(SqStack &S)
{
if(S.top==S.base)
return false;
*S.top--;
return true;
}
//取栈顶元素
bool GetTop(SqStack &S)
{
if(S.top!=S.base)
cout<<*(S.top-1)<<endl;
}
int main()
{
SqStack S;
InitStack(S);
int n;
cin>>n;
while(n--)
{
int op;
cin>>op;
if(op==1)
{
int x;
cin>>x;
Push(S,x);
}
else if(op==2)
Pop(S);
else GetTop(S);
}
return 0;
}
5.链栈的基本操作
有n个操作,每个操作一个整数op:
op==1:输入x入栈;
op==2:弹出栈顶元素;
op==3:输出栈顶元素;
#include<iostream>
using namespace std;
typedef struct StackNode{
int data;
struct StackNode *next;
}StackNode,*LinkStack;
void InitStack(LinkStack &S)
{
S=NULL;
}
bool Push(LinkStack &S,int e)
{
LinkStack p=new StackNode;
p->data=e;
p->next=S;
S=p;
return true;
}
bool Pop(LinkStack &S,int e)
{
if(S==NULL) return false;
e=S->data;
LinkStack p=S;
S=S->next;
delete p;
return true;
}
int GetTop(LinkStack &S)
{
if(S!=NULL)
return S->data;
}
int main()
{
LinkStack S;
InitStack(S);
int n;
cin>>n;
while(n--)
{
int op,x;
cin>>op;
if(op==1)
{
cin>>x;
Push(S,x);
}
else if(op==2)
{
Pop(S,x);
}
else
{
cout<<GetTop(S)<<endl;
}
}
return 0;
}
6.二叉树的基本性质
6.1.性质1
在二叉树的第i层上至多有2^(i-1)(i>=1)个结点。
证明:归纳法容易证得次性质。
i=1时,只有一个根结点。显然,2^(i-1)=2^0=1.
假设对所有的j(1<=j<i)时命题成立,即第j层至多有2^(j-1)个结点。那么,可以证明j=i时命题也成立,则由归纳法即证次性质。
6.2.性质2
深度为k的二叉树至多有2^(k)-1个结点,(k>=1)。
6.3.性质3
对任何一个二叉树T,如果其终端结点树为n0,度为2的结点树为n2,则n0=n2+1.
6.4.性质4
具有n个结点的完全二叉树的深度为[log2 n]+1。
6.5.性质5
如果对一颗有n个结点的完全二叉树(其深度为[log2 n]+1)的结点按照层序编号从第一层到第[log2 n]+1层,每层从左到右),对于任意结点i(1<=i<=n),一下结论成立:
(1).如果i=1,则结点i是二叉树的根,无双亲;如果i>1,其双亲PARENT(i)是结点[i/2];
(2).如果2*i>n,则结点i没有左孩子(结点i为叶子结点);否则其左孩子LCHILD(i)是结点2*i。
(3).如果2*i+1>n,则结点i于有孩子;否则其右孩子RECHILD(i)是结点2*i+1。
6.6.性质6
具有n个结点的不同形态的二叉树的数目符合卡特兰树:Cn 2n/(n+1).
卡特兰数的几何意义:
从(0,0)走到(n,n)且不超过x<=y这条直线的所有方案数。相当于从(0,0)走到(n,n)所有方案数减去超过这条线的方案数,如图:
6.7. 性质7
具有n个结点的不同形态的数的数目等于n-1个结点的不同形态的二叉树的数目。
7.二叉树的基本操作
7.1.二叉树的定义
typedef struct BiTree{
char data;
struct BiTLNode *lchild,*rchild;//左右子树
}BiTLNode,*BiTree;
7.2.二叉树的遍历
//先序递归遍历,根、左、右
void InOrderTraverse1(BiTree T)
{
if(T)
{
cout<<T->data<<" ";
InOrderTraverse(T->lchild); //递归遍历左子树
InOrderTraverse(T->rchild); //递归遍历右子树
}
}
//中序递归遍历,左、根、右
void InOrderTraverse2(BiTree T)
{
if(T)
{
InOrderTraverse2(T->lchild);
cout<<T->data<<" ";
InOrderTraverse2(T->rchild);
}
}
//后序递归遍历,左、右、根
void InOrderTraverse3(BiTree T)
{
if(T)
{
InOrderTraverse3(T->lchild);
InOrderTraverse3(T->rchild);
cout<<T->data<<" ";
}
}
7.3.二叉树的创建
//二叉树的先序创建
void CreateBiTree1(BiTree T)
{
char ch;
cin>>ch;
if(ch=='#') T=NULL;
else
{
T=new BiTLNode;
T->data=ch;
CreateBiTree1(T->lchild);
CreateBiTree1(T->rchild);
}
}
//二叉树的中序遍历
void CreateBiTree(BiTree T)
{
char ch;
cin>>ch;
if(ch=='#') T=NULL:
else
{
T=new BiTLNode;
CreateBiTree(T->lchild);
T->data=ch;
CreateBiTree(T->rchild);
}
}
//二叉树的后序遍历
void CreateBiTree3(BiTree T)
{
char ch;
cin>>ch;
if(ch=='#') T=NULL;
else
{
T=new BiTree;
CreateBiTree(T->lchild);
CreateBiTree(T->rchild);
T->data=ch;
}
}
7.4. 二叉树的复制
void Copy(BiTree T,BiTree &NewT)
{
if(T==NULL)
{
NewT=NULL;
return;
}
else
{
NewT=new BiTLNode;
NewT->data=T->data;
Copy(T->lchild,NewT->lchild);
Copy(T->rchild,NewT->rchild);
}
}
7.5.计算二叉树的深度
int Depth(BiTree T)
{
if(T==NULL) return 0;
else
{
int l=Depth(T->lchild);
int r=Depth(T->rchild);
if(l>r) return (l+1);
else return (r+1);
}
}
7.6.统计二叉树叶子结点的个数
int NodeCount(BiTree T)
{
if(T==NULL) return 0;
int cnt=0;
if((!T->lchild)&&(!T->rchild)) cnt++;
int l=NodeCount(T->lchild);
int r=NodeCount(T->rchild);
cnt+=l+r;
return cnt;
}
7.7.交换左右子树
void ExchangeTree(BiTree T,BiTree &NewT)
{
if(T==NULL)
{
NewT=NULL;
return ;
}
else
{
NewT=new BiTLNode;
NewT->data=T->data;
ExchangeTree(T->lchild,NewT->rchild);
ExchangeTree(T->rchild,NewT->lchild);
}
}
7.8.统计度为1的结点个数
int LNodeCount1(BiTree T)
{
if(T==NULL) return 0;
int cnt=0;
if((T->lchild==NULL&&T->rchild!=NULL)||(T->lchild!=NULL&&T->rchild==NULL))
cnt++;
int l=LNodeCount1(T->lchild);
int r=LNodeCount1(T->rchild):
cnt+=l+r;
return cnt;
}
7.9.总代码
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
typedef struct BiTLNode{
char data;
struct BiTLNode *lchild,*rchild;
}BiTLNode,*BiTree;
//先序遍历
void InOrderTraverse1(BiTree T)
{
if(T)
{
cout<<T->data<<" ";
InOrderTraverse1(T->lchild);
InOrderTraverse1(T->rchild);
}
}
//中序遍历
void InOrderTraverse2(BiTree T)
{
if(T)
{
InOrderTraverse2(T->lchild);
cout<<T->data<<" ";
InOrderTraverse2(T->rchild);
}
}
//后序遍历
void InOrderTraverse3(BiTree T)
{
if(T)
{
InOrderTraverse3(T->lchild);
InOrderTraverse3(T->rchild);
cout<<T->data<<" ";
}
}
//先序创建二叉树
void CreateBiTree(BiTree &T)
{
char ch;
cin>>ch;
if(ch=='#') T=NULL;
else
{
T=new BiTLNode;
T->data=ch;
CreateBiTree(T->lchild);
CreateBiTree(T->rchild);
}
}
void Copy(BiTree T,BiTree &NewT)
{
if(T==NULL)
{
NewT=NULL;
return ;
}
else
{
NewT=new BiTLNode;
NewT->data=T->data;
Copy(T->lchild,NewT->lchild);
Copy(T->rchild,NewT->rchild);
}
}
//计算二叉树的深度
int Depth(BiTree T)
{
if(T==NULL) return 0;
else
{
int l=Depth(T->lchild);
int r=Depth(T->rchild);
if(l>r) return (l+1);
else return (r+1);
}
}
//统计二叉树叶子结点的个数
int NodeCount(BiTree T)
{
if(T==NULL) return 0;
int cnt=0;
if((!T->lchild)&&(!T->rchild)) cnt++;
int l=NodeCount(T->lchild);
int r=NodeCount(T->rchild);
cnt+=l+r;
return cnt;
}
//交换左右子树
void ExchangeTree(BiTree T,BiTree &NewT)
{
if(T==NULL)
{
NewT=NULL;
return ;
}
else
{
NewT=new BiTLNode;
NewT->data=T->data;
ExchangeTree(T->lchild,NewT->rchild);
ExchangeTree(T->rchild,NewT->lchild);
}
}
//统计度为1结点数目
int LNodeCount1(BiTree T)
{
if(T==NULL) return 0;
int cnt=0;
if((T->lchild==NULL&&T->rchild!=NULL)||(T->lchild!=NULL&&T->rchild==NULL))
cnt++;
int l=LNodeCount1(T->lchild);
int r=LNodeCount1(T->rchild);
cnt+=l+r;
return cnt;
}
void menu()
{
cout<<"**************"<<endl;
cout<<"1.创建二叉树"<<endl;
cout<<"2.先序遍历二叉树"<<endl;
cout<<"3.中序遍历二叉树"<<endl;
cout<<"4.后序遍历二叉树"<<endl;
cout<<"5.计算二叉树的深度"<<endl;
cout<<"6.计算二叉树叶子结点的个数"<<endl;
cout<<"7.复制相同的树"<<endl;
cout<<"8.交换左右子树"<<endl;
cout<<"9.统计度为1结点的个数"<<endl;
cout<<"10.退出"<<endl;
cout<<"**************"<<endl;
}
int main()
{
BiTree T;
while(1)
{
menu();
cout<<"请选择:"<<endl;
int op;
cin>>op;
if(op==1)
{
cout<<"请输入所要创建的二叉树:"<<endl;
CreateBiTree(T);
}
else if(op==2)
{
cout<<"先序遍历结果为:";
InOrderTraverse1(T);
cout<<endl;
}
else if(op==3)
{
cout<<"中序遍历结果为:";
InOrderTraverse2(T);
cout<<endl;
}
else if(op==4)
{
cout<<"后序遍历结果为:";
InOrderTraverse3(T);
cout<<endl;
}
else if(op==5)
{
cout<<"树的深度为:";
cout<<Depth(T)<<endl;
}
else if(op==6)
{
cout<<"叶子结点的数目为:"<<endl;
cout<<NodeCount(T)<<endl;
}
else if(op==7)
{
BiTree P;
Copy(T,P);
cout<<"复制后:";
InOrderTraverse1(P);
cout<<endl;
}
else if(op==8)
{
BiTree P;
ExchangeTree(T,P);
cout<<"交换后的值为:";
InOrderTraverse1(P);
cout<<endl;
}
else if(op==9)
{
cout<<"度为1的结点的数目为:";
cout<<LNodeCount1(T)<<endl;
}
else if(op==10)
{
cout<<"已退出!"<<endl;
break;
}
else
{
cout<<"输入错误,请重新输入!"<<endl;
}
}
return 0;
}
10.调试
输入的样例图
简化为:ABC##DE#G##F###