经典数据结构

目录

1.复数的计算

2.单链表

2.1.单链表的定义。

2.2.定义一个为L的单链表。

2.3.交换第k个节点,和第k+1个节点的值。

2.4.如果有LNode *p,*s,若p指向其中一个节点(该节点不为空),s指向一个新的节点,要求:

(1).在p后面插入节点s。

(2).在p节点前插入s。

第一种方法:

第二种方法:

2.5.求单链表的长度

2.6.按下标取单链表中的某个元素。

2.7.按值查找操作

2.8.插入元素

2.9.删除操作

2.10.建立单链表

(1).头插法

(2).尾插法

2.11.实现

2.12.把负数放在正数前面(1)

2.13.把负数放在正数前面(2)

2.14.找单链表数据域最大值

2.15.合并两个有序单链表

2.16.单链表去重

2.17.单链表逆置

2.18.单链表(删除大于mink小于maxk的结点)

2.19.单链表按值删除

2.20.经典问题

2.21.找有序单链表中的中位数

2.22.从尾到头打印单链表

3.单循环链表

3.1.单循环链表的定义

3.2.初始化

3.3.头插法建表

3.4.尾插法

3.5.求链表长度

4.顺序栈的基本操作

5.链栈的基本操作

6.二叉树的基本性质

6.1.性质1

6.2.性质2

6.3.性质3

6.4.性质4

6.5.性质5

6.6.性质6

卡特兰数的几何意义:

6.7. 性质7

7.二叉树的基本操作 

7.1.二叉树的定义

7.2.二叉树的遍历

7.3.二叉树的创建

7.4. 二叉树的复制

7.5.计算二叉树的深度

7.6.统计二叉树叶子结点的个数

7.7.交换左右子树

7.8.统计度为1的结点个数

7.9.总代码

10.调试

输入的样例图


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###

  • 2
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值