zoukankan      html  css  js  c++  java
  • 数据结构回顾

    关于指针的一点知识

    易错点:不要以为指针作为形参传递就可以更改指针本身,只能改变指针指向对象的取值,指针本身的指向是不会变的!!记住任何参数传递都是值传递!

    这种情况下的解决方法有两种:1)传递指针的指针或者指针的引用。2)将改变后的指针值作为函数的返回值

    递归传参 1)全局变量;2)递归函数参数<函数内外定义 both ok>;3)返回值

    第二点:声明(定义)时候的*增加指针维度;使用时候的*和[]减少指针维度;使用时候的&增加指针维度。

    利用new方法获得的都是指针类型变量,指针指向的对象存储在堆空间;通过声明得到的是对象变量,对象存储在栈空间。

    数组与指针

    新建int型变量: int* a=new int; *a=3; 事实上很少这么用的,直接int a=3即可

    新建int数组:int* a=new int[2]; int*p=a;*p=1;*(p+1)=2;*(p+2)=3;

     对于int a[3][4]

    &a 的类型是:   类型(int*)[3][4];   步长为3*4*4=48,即跳跃整个数组;  sizeof(&a)=4;

    a的类型是:  类型(int*)[4]    步长为4*4=16,即跳跃一整行;  sizeof(a)=3*4*4=48;

    *a的类型是:  类型int*;  步长为4,也即跳跃单个元素;  sizeof(*a)=4

    **a的类型是:  类型int;  不是指针,不存在步长的说法;  sizeof(**a)=4

      

    对于int** a[3][4]

    []的结核性从左到右,比*高,因此这是一个二维指针数组;数组中的元素是指向int型指针的指针

    对于int*(*a)[3][4]

    这是一个数组指针,指针指向一个二维数组,数组中的元素是int*类型

     

    int* (*a)[3][4]

    int a=3; int *p=&a;

    printf("%d",p);得到的是一个地址

    printf("%d",*p);得到p指向地址存储变量的内容,也就是a:3

    free(p);之后,p这个地址变量指向的地址不知道了,变成了野指针,供操作系统再次分配。无论是对p的调用还是对*p的调用都会造成段错误。

    p=NULL之后,printf("%d",p)得到0;printf("%d",*p);引发段错误。

    还有记得,c语言是一句一句顺序执行的

    指针相关的运算符:
    
    指针变量,存放的是所指向变量的地址
    
    &取地址运算符:去除变量所在的地址
    
    *取出所指向地址处变量的内容,而不是取出指针变量中的地址
    
    指针相关运算符的优先级别以及结合顺序:
    
    ()、[]、->、. :优先级为1,结合性为自左向右
    
    * & 优先级为2,结合性为自右向左
    
    ->是指向结构体变量的运算符
    
    如果p是指向结构体变量的指针,那么(*p).num和p->num的效果相同。
    
    数组相关的指针:
    
    对于a[2][3]
    
    a代表的是二维数组首行的地址,a+1代表第一行的首地址,变化的幅度为行。
    
    a[0]、a[1]是以为数组名。变化的幅度为一个元素。
    
    a[1]和*(a+1)的效果是一样的。
    
    int a[n] 定义整型数组a,它有n个元素
    
    int *a[n]定义指针数组a,它由n个指向整形数据的指针元素构成
    
    int (*p)[n] p为指向含n个元素的以为数组的指针变量
    
    int (*p) ();指向函数的指针
    
    int **p指向指针的指针
    
    int *p() 返回类型为指针型变量的函数
    
    关于空指针,指针变量为空,指针指向空
    
    int *p;
    
    p=null;
    
    *p=null;
    
    空指针是指指针指向的内容为空,空指针是不能操作的,否则会引发所谓的空指针异常(就是一个指针是空指针,你还要去操作它,既然它指向的是空对象,它就不能使用这个对象的方法。)
    
    p=null,一般用于指针变量的初始化,否则系统会随机给它分配一个地址。但是它可以指向其他变量。在free之后,也一般蒋指针置为空,代表指着目前不指向任何对象。防止误操作。
    
    free(p)的含义是值蒋指针指向的内存空间清空,交还给操作系统,而指针本身仍存在,因为指针是一个变量,只有程序结束时才被销毁,只不过现在指针指向的内容是无用的,未定义的。因此,释放内存后通常把指针指向 NULL,即p=NULL,防止指针在 后面不小心又被引用。
    
    指针为空(p=NULL)代表该指针没有指向任何变量。
    
    空指针(*p=NULL)(指针内容为空)代表指针指向的变量为空。
    关于指针的一点知识
    #include "stdio.h"    
    #include "string.h"
    #include "ctype.h"      
    #include "stdlib.h"   
    #include "math.h"  
    #include "time.h"
    
    #define OK 1
    #define ERROR 0
    #define TRUE 1
    #define FALSE 0
    
    #define MAXSIZE 20 /* 存储空间初始分配量 */
    
    typedef int Status;/* Status是函数的类型,其值是函数结果状态代码,如OK等 */
    typedef int ElemType;/* ElemType类型根据实际情况而定,这里假设为int */
    
    
    Status visit(ElemType c)
    {
        printf("%d ",c);
        return OK;
    }
    
    typedef struct Node
    {
        ElemType data;
        struct Node *next;
    }Node, *LinkList;
    
    /* 初始化顺序线性表 */
    Status InitList(LinkList *L) 
    { 
        //创建一个头节点,不过该节点并不存放元素
        *L=(Node*)malloc(sizeof(Node));
        (*L)->next=NULL;
        return OK;
    }
    
    /* 初始条件:顺序线性表L已存在。操作结果:若L为空表,则返回TRUE,否则返回FALSE */
    Status ListEmpty(LinkList L)
    { 
        if(L->next==NULL){
            return TRUE;
        }else{
            return FALSE;
        }
    }
    
    /* 初始条件:顺序线性表L已存在。操作结果:将L重置为空表,但是并不彻底删除 */
    Status ClearList(LinkList *L)
    { 
        if(ListEmpty(*L)){
            return ERROR;
        }
        Node *p=(*L)->next;
        Node* q=NULL;
        while(p){
            q=p->next;
            free(p);
            p=q;
        }
        (*L)->next=NULL;
        return OK;
    
    }
    
    /* 初始条件:顺序线性表L已存在。操作结果:返回L中数据元素个数 */
    int ListLength(LinkList L)
    {
        if(ListEmpty(L)){
            return 0;
        }
        int length=0;
        Node *p=L->next;
        while(p){
            length++;
            p=p->next;
        }
        return length;
    }
    
    /* 初始条件:顺序线性表L已存在,1≤i≤ListLength(L) */
    /* 操作结果:用e返回L中第i个数据元素的值 */
    Status GetElem(LinkList L,int i,ElemType *e)
    {
        Node *p=L->next;
        int j=1;
        while(p&&j<i){
            p=p->next;
            j++;
        }
        if(j==i){
            *e=p->data;
        }else{
            return ERROR;
        }
        
        return OK;
    }
    
    /* 初始条件:顺序线性表L已存在 */
    /* 操作结果:返回L中第1个与e满足关系的数据元素的位序。 */
    /* 若这样的数据元素不存在,则返回值为0 */
    int LocateElem(LinkList L,ElemType e)
    {
        int i=1;
        Node *p=L->next;
        while(p){
            if(p->data==e){
                return i;
            }
            i++;
            p=p->next;
        }
        if(!p){
            return 0;    
        }
        
    }
    
    
    /* 初始条件:顺序线性表L已存在,1≤i≤ListLength(L), */
    /* 操作结果:在L中第i个位置之前插入新的数据元素e,L的长度加1 */
    Status ListInsert(LinkList *L,int i,ElemType e)
    { 
        if(i>ListLength(*L)+1){
            return ERROR;
        }
        Node *p=*L;
        int j=1;
        while(p&&j<i){
            p=p->next;
            j++;
        }
    
        
        Node *node=(Node*)malloc(sizeof(Node));
        node->data=e;
        node->next=p->next;
        p->next=node;
        return OK;
    }
    
    /* 初始条件:顺序线性表L已存在,1≤i≤ListLength(L) */
    /* 操作结果:删除L的第i个数据元素,并用e返回其值,L的长度减1 */
    Status ListDelete(LinkList *L,int i,ElemType *e) 
    { 
        if(ListEmpty(*L)||i>ListLength(*L)){
            return ERROR;
        }
        int j=1;
        Node *p=*L;
        while(p&&j<i){
            p=p->next;
            j++;
        }
        Node *q=p->next;
        p->next=q->next;
        *e=q->data;
        free(q);
        q=NULL;
        return OK;
    
    }
    
    /* 初始条件:顺序线性表L已存在 */
    /* 操作结果:依次对L的每个数据元素输出 */
    Status ListTraverse(LinkList L)
    {
        if(ListEmpty(L)){
            return ERROR;
        }
        Node *p=L->next;
        while(p){
            visit(p->data);
            p=p->next;
        }
        printf("
    ");
        return OK;
    }
    
    /*  随机产生n个元素的值,建立带表头结点的单链线性表L(头插法) */
    void CreateListHead(LinkList *L, int n) 
    {
        //首先进行初始化
        InitList(L);
        srand(time(0));
        int i;
        for(i=0;i<n;i++){
        Node *node=(Node*)malloc(sizeof(Node));
        if(!node){
            exit(OVERFLOW);
        }
        node->data=rand()%100+1;
        node->next=(*L)->next;
        (*L)->next=node;
        }
    }
    
    /*  随机产生n个元素的值,建立带表头结点的单链线性表L(尾插法) */
    void CreateListTail(LinkList *L, int n) 
    {
        InitList(L);
        srand(time(0));
        int i;
        Node *p=*L;
        for(i=0;i<n;i++){
            Node *node=(Node*)malloc(sizeof(Node));
            if(!node){
                exit(OVERFLOW);
            }
            node->data=rand()%100+1;
            node->next=NULL;
            p->next=node;
            p=node;
        }
    }
    
    int main()
    {        
        LinkList L;
        ElemType e;
        Status i;
        int j,k;
        i=InitList(&L);
        printf("初始化L后:ListLength(L)=%d
    ",ListLength(L));
        for(j=1;j<=5;j++)
                i=ListInsert(&L,1,j);
        printf("在L的表头依次插入1~5后:L.data=");
        ListTraverse(L); 
    
        printf("ListLength(L)=%d 
    ",ListLength(L));
        i=ListEmpty(L);
        printf("L是否空:i=%d(1:是 0:否)
    ",i);
    
        i=ClearList(&L);
        printf("清空L后:ListLength(L)=%d
    ",ListLength(L));
        i=ListEmpty(L);
        printf("L是否空:i=%d(1:是 0:否)
    ",i);
    
        for(j=1;j<=10;j++)
                ListInsert(&L,j,j);
        printf("在L的表尾依次插入1~10后:L.data=");
        ListTraverse(L); 
    
        printf("ListLength(L)=%d 
    ",ListLength(L));
    
        ListInsert(&L,1,0);
        printf("在L的表头插入0后:L.data=");
        ListTraverse(L); 
        printf("ListLength(L)=%d 
    ",ListLength(L));
    
        GetElem(L,5,&e);
        printf("第5个元素的值为:%d
    ",e);
        for(j=3;j<=4;j++)
        {
                k=LocateElem(L,j);
                if(k)
                        printf("第%d个元素的值为%d
    ",k,j);
                else
                        printf("没有值为%d的元素
    ",j);
        }
        
    
        k=ListLength(L); /* k为表长 */
        for(j=k+1;j>=k;j--)
        {
                i=ListDelete(&L,j,&e); /* 删除第j个数据 */
                if(i==ERROR)
                        printf("删除第%d个数据失败
    ",j);
                else
                        printf("删除第%d个的元素值为:%d
    ",j,e);
        }
        printf("依次输出L的元素:");
        ListTraverse(L); 
    
        j=5;
        ListDelete(&L,j,&e); /* 删除第5个数据 */
        printf("删除第%d个的元素值为:%d
    ",j,e);
    
        printf("依次输出L的元素:");
        ListTraverse(L); 
    
        i=ClearList(&L);
        printf("
    清空L后:ListLength(L)=%d
    ",ListLength(L));
        CreateListHead(&L,20);
        printf("整体创建L的元素(头插法):");
        ListTraverse(L); 
        
        i=ClearList(&L);
        printf("
    删除L后:ListLength(L)=%d
    ",ListLength(L));
        CreateListTail(&L,20);
        printf("整体创建L的元素(尾插法):");
        ListTraverse(L); 
    
    
        return 0;
    }
    线性单链表的实现

    1)上例实现的是带有头节点(头节点不存放具体元素)的单链表。

    2)注意链表的清空操作。

     关于链表的一些面试题目:

    (注意以下实现都是基于不包含头节点的链表)

    A。链表的逆序(关键在于3个指针,指向相邻的3个元素)

    #include "stdio.h"    
    #include "string.h"
    #include "ctype.h"      
    #include "stdlib.h"   
    #include "math.h"  
    #include "time.h"
    
    #define OK 1
    #define ERROR 0
    #define TRUE 1
    #define FALSE 0
    
    #define MAXSIZE 20 /* 存储空间初始分配量 */
    
    typedef int Status;/* Status是函数的类型,其值是函数结果状态代码,如OK等 */
    typedef int ElemType;/* ElemType类型根据实际情况而定,这里假设为int */
    
    
    Status visit(ElemType c)
    {
        printf("%d ",c);
        return OK;
    }
    
    typedef struct Node
    {
        ElemType data;
        struct Node *next;
    }Node, *LinkList;
    
    /* 初始化顺序线性表 */
    Status InitList(LinkList *L) 
    { 
        //创建一个头节点,不过该节点并不存放元素
        *L=(Node*)malloc(sizeof(Node));
        (*L)->next=NULL;
        return OK;
    }
    
    /* 初始条件:顺序线性表L已存在。操作结果:若L为空表,则返回TRUE,否则返回FALSE */
    Status ListEmpty(LinkList L)
    { 
        if(L->next==NULL){
            return TRUE;
        }else{
            return FALSE;
        }
    }
    
    /* 初始条件:顺序线性表L已存在。操作结果:将L重置为空表,但是并不彻底删除 */
    Status ClearList(LinkList *L)
    { 
        if(ListEmpty(*L)){
            return ERROR;
        }
        Node *p=(*L)->next;
        Node* q=NULL;
        while(p){
            q=p->next;
            free(p);
            p=q;
        }
        (*L)->next=NULL;
        return OK;
    
    }
    
    /* 初始条件:顺序线性表L已存在。操作结果:返回L中数据元素个数 */
    int ListLength(LinkList L)
    {
        if(ListEmpty(L)){
            return 0;
        }
        int length=0;
        Node *p=L->next;
        while(p){
            length++;
            p=p->next;
        }
        return length;
    }
    
    /* 初始条件:顺序线性表L已存在,1≤i≤ListLength(L) */
    /* 操作结果:用e返回L中第i个数据元素的值 */
    Status GetElem(LinkList L,int i,ElemType *e)
    {
        Node *p=L->next;
        int j=1;
        while(p&&j<i){
            p=p->next;
            j++;
        }
        if(j==i){
            *e=p->data;
        }else{
            return ERROR;
        }
        
        return OK;
    }
    
    /* 初始条件:顺序线性表L已存在 */
    /* 操作结果:返回L中第1个与e满足关系的数据元素的位序。 */
    /* 若这样的数据元素不存在,则返回值为0 */
    int LocateElem(LinkList L,ElemType e)
    {
        int i=1;
        Node *p=L->next;
        while(p){
            if(p->data==e){
                return i;
            }
            i++;
            p=p->next;
        }
        if(!p){
            return 0;    
        }
        
    }
    
    
    /* 初始条件:顺序线性表L已存在,1≤i≤ListLength(L), */
    /* 操作结果:在L中第i个位置之前插入新的数据元素e,L的长度加1 */
    Status ListInsert(LinkList *L,int i,ElemType e)
    { 
        if(i>ListLength(*L)+1){
            return ERROR;
        }
        Node *p=*L;
        int j=1;
        while(p&&j<i){
            p=p->next;
            j++;
        }
    
        
        Node *node=(Node*)malloc(sizeof(Node));
        node->data=e;
        node->next=p->next;
        p->next=node;
        return OK;
    }
    
    /* 初始条件:顺序线性表L已存在,1≤i≤ListLength(L) */
    /* 操作结果:删除L的第i个数据元素,并用e返回其值,L的长度减1 */
    Status ListDelete(LinkList *L,int i,ElemType *e) 
    { 
        if(ListEmpty(*L)||i>ListLength(*L)){
            return ERROR;
        }
        int j=1;
        Node *p=*L;
        while(p&&j<i){
            p=p->next;
            j++;
        }
        Node *q=p->next;
        p->next=q->next;
        *e=q->data;
        free(q);
        q=NULL;
        return OK;
    
    }
    
    /* 初始条件:顺序线性表L已存在 */
    /* 操作结果:依次对L的每个数据元素输出 */
    Status ListTraverse(LinkList L)
    {
        if(ListEmpty(L)){
            return ERROR;
        }
        Node *p=L->next;
        while(p){
            visit(p->data);
            p=p->next;
        }
        printf("
    ");
        return OK;
    }
    
    /*  随机产生n个元素的值,建立带表头结点的单链线性表L(头插法) */
    void CreateListHead(LinkList *L, int n) 
    {
        //首先进行初始化
        InitList(L);
        srand(time(0));
        int i;
        for(i=0;i<n;i++){
        Node *node=(Node*)malloc(sizeof(Node));
        if(!node){
            exit(OVERFLOW);
        }
        node->data=rand()%100+1;
        node->next=(*L)->next;
        (*L)->next=node;
        }
    }
    
    /*  随机产生n个元素的值,建立带表头结点的单链线性表L(尾插法) */
    void CreateListTail(LinkList *L, int n) 
    {
        InitList(L);
        srand(time(0));
        int i;
        Node *p=*L;
        for(i=0;i<n;i++){
            Node *node=(Node*)malloc(sizeof(Node));
            if(!node){
                exit(OVERFLOW);
            }
            node->data=rand()%100+1;
            node->next=NULL;
            p->next=node;
            p=node;
        }
    }
    //下面是关于链表的一些面试题目
    //已知链表的头节点,写一个函数把这个链表逆序
    void ListReverse(LinkList *L){
    //基本思想是使用3个指针,同时指向相邻的3个元素
        if(ListEmpty(*L)){
            return;
        }
        Node *p=(*L)->next;
        Node *q=p->next;
        p->next=NULL;
        Node *r=NULL;
        while(q){
            r=q->next;
            q->next=p;
            p=q;
            q=r;
        }
        (*L)->next=p;
    }
    
    
    int main()
    {        
        LinkList L;
        ElemType e;
        Status i;
        int j,k;
        i=InitList(&L);
        printf("初始化L后:ListLength(L)=%d
    ",ListLength(L));
        for(j=1;j<=5;j++)
                i=ListInsert(&L,1,j);
        printf("在L的表头依次插入1~5后:L.data=");
        ListTraverse(L); 
        printf("ListLength(L)=%d 
    ",ListLength(L));
        ListReverse(&L);
        printf("链表逆序之后,ListLength(L)=%d; 
    L.data=",ListLength(L));
       ListTraverse(L);
        i=ListEmpty(L);
        printf("L是否空:i=%d(1:是 0:否)
    ",i);
    
        i=ClearList(&L);
        printf("清空L后:ListLength(L)=%d
    ",ListLength(L));
        i=ListEmpty(L);
        printf("L是否空:i=%d(1:是 0:否)
    ",i);
    
        for(j=1;j<=10;j++)
                ListInsert(&L,j,j);
        printf("在L的表尾依次插入1~10后:L.data=");
        ListTraverse(L); 
    
        printf("ListLength(L)=%d 
    ",ListLength(L));
    
        ListInsert(&L,1,0);
        printf("在L的表头插入0后:L.data=");
        ListTraverse(L); 
        printf("ListLength(L)=%d 
    ",ListLength(L));
    
        GetElem(L,5,&e);
        printf("第5个元素的值为:%d
    ",e);
        for(j=3;j<=4;j++)
        {
                k=LocateElem(L,j);
                if(k)
                        printf("第%d个元素的值为%d
    ",k,j);
                else
                        printf("没有值为%d的元素
    ",j);
        }
        
    
        k=ListLength(L); /* k为表长 */
        for(j=k+1;j>=k;j--)
        {
                i=ListDelete(&L,j,&e); /* 删除第j个数据 */
                if(i==ERROR)
                        printf("删除第%d个数据失败
    ",j);
                else
                        printf("删除第%d个的元素值为:%d
    ",j,e);
        }
        printf("依次输出L的元素:");
        ListTraverse(L); 
    
        j=5;
        ListDelete(&L,j,&e); /* 删除第5个数据 */
        printf("删除第%d个的元素值为:%d
    ",j,e);
    
        printf("依次输出L的元素:");
        ListTraverse(L); 
    
        i=ClearList(&L);
        printf("
    清空L后:ListLength(L)=%d
    ",ListLength(L));
        CreateListHead(&L,20);
        printf("整体创建L的元素(头插法):");
        ListTraverse(L); 
        
        i=ClearList(&L);
        printf("
    删除L后:ListLength(L)=%d
    ",ListLength(L));
        CreateListTail(&L,20);
        printf("整体创建L的元素(尾插法):");
        ListTraverse(L); 
    
    
        return 0;
    }
    包含头节点的链表的逆序实现
    //对链表进行逆转
    Status ListReverse(LinkList *L){
    //含有头节点的话,第一个和最后一个都需要进行额外处理
        Node *p=(*L);
        Node *q=(*L)->next;
        Node *r=NULL;
        while(q){
            r=q->next;
            q->next=p;
            p=q;
            q=r;
        }
        (*L)->next=NULL;
        *L=p;
        return OK;
    }
    不包含头节点的链表的逆序实现

     B。两个有序链表的合并

    /无头节点链表合并的非递归方法
    LinkList mergeSortedList(LinkList L1,LinkList L2){
        LinkList L=(LinkList)malloc(sizeof(Node));
        L->next=NULL;
        Node *p1=L1;
        Node *p2=L2;
        Node *p=NULL;
        //没有头节点的链表,对于第一个需要额外处理
        if(p1->data<=p2->data){
            L=p1;
            p1=p1->next;
    
        }else{
            L=p2;
            p2=p2->next;
        }    
        p=L;
        while(p1&&p2){
            if(p1->data<=p2->data){
                p->next=p1;
                p1=p1->next;
                p=p->next;
                
            }else if(p1->data>p2->data){
                p->next=p2;
                p2=p2->next;
                p=p->next;
            }
        }
            p->next=p1?p1:p2;    
            return L;
    }
    无头节点链表合并的非递归方法
    //采用递归的方法实现无头节点链表的合并,每次递归返回合并后新链表的头部节点
    //递归中的局部变量一般是无意义的,除非该局部变量作为函数返回值返回,(如果作为下一次递归的调用参数呢?)
    //关于理解递归的一种方法,把它当作另外一个函数,只是样子长得一样而已
    LinkList recursiveMergeSortedList(LinkList L1,LinkList L2){
        //ListTraverse(L1);
        //ListTraverse(L2);
        if(!L1||!L2){
            return L1?L1:L2;
        }
        Node *node;
        if(L1->data<=L2->data){
            node=L1;
            node->next=recursiveMergeSortedList(L1->next,L2);
        }else if(L1->data>L2->data){
            node=L2;
            node->next=recursiveMergeSortedList(L1,L2->next);
        }
        return node;
    
    }
    无头节点链表合并的递归方法
    //合并两个带有头节点的有序单链表,这种方法的漏洞是没有考虑两条链表有交集的情况
    LinkList mergeSortedList(LinkList L1,LinkList L2){
        LinkList L;
        InitList(&L);
        LinkList p=L;
        Node* pa=L1->next;
        Node* pb=L2->next;
        while(pa&&pb){
            if(pa->data<=pb->data){
                p->next=pa;
                p=pa;
                pa=pa->next;
            }else{
                p->next=pb;
                p=pb;
                pb=pb->next;
            }
        }
        if(pa==NULL){
            p->next=pb;
        }else if(pb=NULL){
            p->next=pa;
        }
        return L;
    
    }
    包含头节点有序链表合并的非递归方法
    和不含头节点的递归实现相同,只不过在函数调用之前,蒋传入参数和返回值处理成不包含头节点的情况
    含有头节点的链表合并的递归实现

     (思考,这个代码是否有问题?如果两个链表有交集呢?)

    C。寻找链表的中间节点(采取两个指针,一个步长为1,一个步长为2,步长为2的为空的时候,另外一个刚好走到中间)

     //找出单向链表的中间节点
    Node* middleNode(LinkList L){ 
            Node *p; 
            Node *q; 
            p=L;
            q=L;
            while(q){
                    q=q->next->next;
                    p=p->next;
            }   
            return p;
    }
    找出链表的中间节点

    D判断链表是否有环(使用步长为1和步长为2的两个指针,如果两个指针相遇,说明有环,否则无环)

    其他题目:

    1,找出链表的倒数第k个元素

    2,找出链表的中间元素

    (一快一慢两个指针)

    3,找出链表环的入口

    设链头到入口的距离为a,相遇的地方距离入口为x,环的长度为r;那么有2*(a+x)=a+x+nr;所以又a=(n-1)r+r-x

    1)让一快(2)一慢(1)两个指针一起走直到相遇

    2)之后让两个指针一起走,步长皆为1,一个从头开始走,另外一个从相遇的地方开始走,那么再次相遇的地方即是入口。

    4,判断两个链表是否相交,如果相交,找出交点

    1)两个相交的链表一定要不都没有环,要么都有环

    2)如果两个链表都没有环,若最后一个节点相同,那么相交;那么找出两个链表的长度m,n,短的从头走,长的从n-m处走,第一次相遇的地方即为交点

    3)如果两个链表都有环,那么判断其中一个链表的入口节点在不在另外一个链表上,如果在,则相交。如果两个链表相交,可以定义任何一个链表的入口节点为交点。


    #include "stdio.h"    
    #include "stdlib.h"   
    #include "math.h"  
    #include "time.h"
    
    #define OK 1
    #define ERROR 0
    #define TRUE 1
    #define FALSE 0
    #define MAXSIZE 20 /* 存储空间初始分配量 */
    
    typedef int Status; 
    typedef int SElemType; /* SElemType类型根据实际情况而定,这里假设为int */
    
    /* 顺序栈结构 */
    typedef struct
    {
        //下标为0的地方为栈底,top指针指向栈顶部
        SElemType data[MAXSIZE];
        int top;
    }SqStack;
    
    Status visit(SElemType c)
    {
        printf("%d ",c);
        return OK;
    }
    
    /*  构造一个空栈S */
    Status InitStack(SqStack *s)
    { 
        s->top=-1;
        return OK;
    }
    
    /* 把S置为空栈 */
    Status ClearStack(SqStack *s)
    { 
        s->top=-1;
        return OK;
    }
    
    /* 若栈S为空栈,则返回TRUE,否则返回FALSE */
    Status StackEmpty(SqStack s)
    { 
        if(s.top==-1){
            return TRUE;
        }else{
            return FALSE;
        }
    }
    /* 若栈不空,则用e返回S的栈顶元素,并返回OK;否则返回ERROR */
    Status GetTop(SqStack s,SElemType *e)
    {
        if(s.top<0){
        return ERROR;
        }
        if(s.top>=MAXSIZE-1){
        return ERROR;
        }
        *e=s.data[s.top];
        return OK;
    }
    
    /* 插入元素e为新的栈顶元素 */
    Status Push(SqStack *s,SElemType e)
    {
        if(s->top>=MAXSIZE-1){
            return ERROR;
        }
        else{
        s->data[++s->top]=e;
        }
        return OK;
    }
    
    /* 若栈不空,则删除S的栈顶元素,用e返回其值,并返回OK;否则返回ERROR */
    Status Pop(SqStack *s,SElemType *e)
    { 
        if(s->top<=0){
        return ERROR;
        }
    
        *e=s->data[s->top];
        s->top--;
        return OK;
        return OK;
    }
    
    /* 从栈底到栈顶依次对栈中每个元素显示 */
    Status StackTraverse(SqStack s)
    {
        if(s.top<=0){
        return ERROR;
        }
        int i;
        for(i=0;i<=s.top;i++){
        visit(s.data[i]);
        }
        printf("
    ");
        return OK;
    }
    int StackLength(SqStack s){
    return ++s.top;
    }
    int main()
    {
            int j;
            SqStack s;
            int e;
            if(InitStack(&s)==OK)
                    for(j=1;j<=10;j++)
                            Push(&s,j);
            printf("栈中元素依次为:");
            StackTraverse(s);
            Pop(&s,&e);
            printf("弹出的栈顶元素 e=%d
    ",e);
            printf("栈空否:%d(1:空 0:否)
    ",StackEmpty(s));
            GetTop(s,&e);
            printf("栈顶元素 e=%d 栈的长度为%d
    ",e,StackLength(s));
            ClearStack(&s);
            printf("清空栈后,栈空否:%d(1:空 0:否)
    ",StackEmpty(s));
            
            return 0;
    }
    顺序栈的实现

    一点总结:

    1)下标为0的数组元素为栈底

    2)top指针时刻指向栈顶元素

    3)初始化的时候,top指针为-1

    #include "stdio.h"    
    #include "stdlib.h"   
    #include "math.h"  
    #include "time.h"
    
    #define OK 1
    #define ERROR 0
    #define TRUE 1
    #define FALSE 0
    #define MAXSIZE 20 /* 存储空间初始分配量 */
    
    typedef int Status; 
    typedef int SElemType; /* SElemType类型根据实际情况而定,这里假设为int */
    
    
    /* 链栈结构 */
    typedef struct StackNode
    {
        SElemType data;
        //指针变量,存放的是所指向变量的地址
        //&取地址运算符
        //*取出其指向地址处变量的内容,而不是取出地址
        struct StackNode *next;
    }StackNode,*LinkStackPtr;
    
    
    typedef struct
    {
        int count;
        LinkStackPtr top;
    }LinkStack;
    
    Status visit(SElemType c)
    {
        printf("%d ",c);
        return OK;
    }
    
    /*  构造一个空栈S */
    Status InitStack(LinkStack *S)
    { 
        S->count=0;
        S->top=NULL;
        return OK;
    }
    
    /* 把S置为空栈 */
    Status ClearStack(LinkStack *S)
    {     
        //需要借助两个中间变量!
        LinkStackPtr p=S->top;
        LinkStackPtr q;
        while(p){
            q=p;
            p=p->next;
            free(q);
        }
    }
    
    /* 若栈S为空栈,则返回TRUE,否则返回FALSE */
    Status StackEmpty(LinkStack S)
    { 
        if(S.count==0){
            return TRUE;
        }else{
            return FALSE;
        }
    }
    
    /* 返回S的元素个数,即栈的长度 */
    int StackLength(LinkStack S)
    { 
        return S.count;
    }
    
    /* 若栈不空,则用e返回S的栈顶元素,并返回OK;否则返回ERROR */
    Status GetTop(LinkStack S,SElemType *e)
    {
        if(StackEmpty(S)){
            return ERROR;
        }
        *e=S.top->data;
        return OK;
    }
    
    /* 插入元素e为新的栈顶元素 */
    Status Push(LinkStack *S,SElemType e)
    {
        LinkStackPtr node=(LinkStackPtr)malloc(sizeof(StackNode));
        node->data=e;
        //头指针就是首元素,因此不是node->next=S->top_>next
        node->next=S->top;
        S->top=node;
        S->count++;
        return OK;
    }
    
    /* 若栈不空,则删除S的栈顶元素,用e返回其值,并返回OK;否则返回ERROR */
    Status Pop(LinkStack *S,SElemType *e)
    {     
        if(StackEmpty(*S)){
            return ERROR;
        }
        LinkStackPtr p=S->top;
         *e=p->data;
         S->top=p->next;
         free(p);
         S->count--;
         return OK;
        
    }
    
    Status StackTraverse(LinkStack S)
    {
        LinkStackPtr p;
        p=S.top;
        while(p){
        visit(p->data);
        p=p->next;
        }
        printf("
    ");
        return OK;
    }
    
    int main()
    {
            int j;
            LinkStack s;
            int e;
            if(InitStack(&s)==OK)
                    for(j=1;j<=10;j++)
                            Push(&s,j);
            printf("栈中元素依次为:");
            StackTraverse(s);
            Pop(&s,&e);
            printf("弹出的栈顶元素 e=%d
    ",e);
            printf("栈空否:%d(1:空 0:否)
    ",StackEmpty(s));
            GetTop(s,&e);
            printf("栈顶元素 e=%d 栈的长度为%d
    ",e,StackLength(s));
            ClearStack(&s);
            printf("清空栈后,栈空否:%d(1:空 0:否)
    ",StackEmpty(s));
            return 0;
    }
    链栈的实现

    一点总结:

    1)链表的头元素作为栈顶元素本身(该链表是不含头节点的单链表,也就是头指针放置具体元素)。

    2)注意栈的清空、插入和删除操作。

    #include "stdio.h"    
    #include "stdlib.h"   
    
    #define OK 1
    #define ERROR 0
    #define TRUE 1
    #define FALSE 0
    #define MAXSIZE 20 /* 存储空间初始分配量 */
    
    typedef int Status; 
    typedef int QElemType; /* QElemType类型根据实际情况而定,这里假设为int */
    
    /* 循环队列的顺序存储结构 */
    typedef struct
    {
        //为了区分队列为空和队列满两种情况,队列为空的时候rear==front;队列满的时候,保留一个元素空间,也就是(rear+1)%MAXSIZE=front;
        QElemType data[MAXSIZE];
        //通过%操作,front 和rear的取值还是始终在0和MAXSIZE之间
        //front指向队列头部元素
        int front;
        //rear指针指向对尾元素的下一个
        int rear;
    
    }SqQueue;
    
    Status visit(QElemType c)
    {
        printf("%d ",c);
        return OK;
    }
    
    /* 初始化一个空队列Q */
    Status InitQueue(SqQueue *Q)
    {
        Q->front=Q->rear=0;
        return OK;
    }
    
    /* 将Q清为空队列 */
    Status ClearQueue(SqQueue *Q)
    {    
        Q->front=Q->rear=0;
        return OK;
    }
    
    /* 若队列Q为空队列,则返回TRUE,否则返回FALSE */
    Status QueueEmpty(SqQueue Q)
    { 
        return Q.front==Q.rear;
    }
    Status QueueFull(SqQueue Q){
        if((Q.rear+1)%MAXSIZE==Q.front){
            return TRUE;
        }else{
            return FALSE;
        }
    
    }
    /* 返回Q的元素个数,也就是队列的当前长度 */
    int QueueLength(SqQueue Q)
    {
        return (Q.rear-Q.front+MAXSIZE)%MAXSIZE;
    }
    
    /* 若队列不空,则用e返回Q的队头元素,并返回OK,否则返回ERROR */
    Status GetHead(SqQueue Q,QElemType *e)
    {    
        if(QueueEmpty(Q)){
            return ERROR;
        }
        *e=Q.data[Q.front];
        return OK;
    }
    
    /* 若队列未满,则插入元素e为Q新的队尾元素 */
    Status EnQueue(SqQueue *Q,QElemType e)
    {
        if(QueueFull(*Q)){
            return ERROR;
        }
        Q->data[Q->rear]=e;
        Q->rear=(Q->rear+1)%MAXSIZE;
        return OK;
        
    }
    
    /* 若队列不空,则删除Q中队头元素,用e返回其值 */
    Status DeQueue(SqQueue *Q,QElemType *e)
    {
        if(QueueEmpty(*Q)){
            return ERROR;
        }
        *e=Q->data[Q->front];
        Q->front=(Q->front+1)%MAXSIZE;
        return OK;
    
    }
    
    /* 从队头到队尾依次对队列Q中每个元素输出 */
    Status QueueTraverse(SqQueue Q)
    { 
        if(QueueEmpty(Q)){
            return ERROR;
        }
    
        int i;
        for(i=Q.front;i<Q.rear;i++){
            visit(Q.data[Q.data[i]]);
        }
        return OK;
    }
    
    int main()
    {
        Status j;
        int i=0,l;
        QElemType d;
        SqQueue Q;
        InitQueue(&Q);
        printf("初始化队列后,队列空否?%u(1:空 0:否)
    ",QueueEmpty(Q));
    
        printf("请输入整型队列元素(不超过%d个),-1为提前结束符: ",MAXSIZE-1);
        do
        {
            /* scanf("%d",&d); */
            d=i+100;
            if(d==-1)
                break;
            i++;
            EnQueue(&Q,d);
        }while(i<MAXSIZE-1);
    
        printf("队列长度为: %d
    ",QueueLength(Q));
        printf("现在队列空否?%u(1:空 0:否)
    ",QueueEmpty(Q));
        printf("连续%d次由队头删除元素,队尾插入元素:
    ",MAXSIZE);
        for(l=1;l<=MAXSIZE;l++)
        {
            DeQueue(&Q,&d);
            printf("删除的元素是%d,插入的元素:%d 
    ",d,l+1000);
            /* scanf("%d",&d); */
            d=l+1000;
            EnQueue(&Q,d);
        }
        l=QueueLength(Q);
    
        printf("现在队列中的元素为: 
    ");
        QueueTraverse(Q);
        printf("共向队尾插入了%d个元素
    ",i+MAXSIZE);
        if(l-2>0)
            printf("现在由队头删除%d个元素:
    ",l-2);
        while(QueueLength(Q)>2)
        {
            DeQueue(&Q,&d);
            printf("删除的元素值为%d
    ",d);
        }
    
        j=GetHead(Q,&d);
        if(j)
            printf("现在队头元素为: %d
    ",d);
        ClearQueue(&Q);
        printf("清空队列后, 队列空否?%u(1:空 0:否)
    ",QueueEmpty(Q));
        return 0;
    }
    顺序循环队列的实现

    1,队头指针指向队头元素本身

    2,对尾指针指向对尾元素的后一个,队头和队尾的取值还是再0-MAXSIZE之间。

    3,队列为空的标志为Q->front==Q->rear

    4,为了防止队列满时候和队列为空的时候,都存在Q->front==Q->rear;规定队列满的时候,保留一个队列空间不放元素,因此队列满的标志为:(Q->rear+1)%MAXSIZE==Q->front;

     5,队列长度为(Q->rear-Q->front+MAXSIZE)%MAXSIZE;

    #include "stdio.h"    
    #include "stdlib.h"   
    #include "math.h"  
    #include "time.h"
    
    #define OK 1
    #define ERROR 0
    #define TRUE 1
    #define FALSE 0
    #define MAXSIZE 20 /* 存储空间初始分配量 */
    
    typedef int Status; 
    
    typedef int QElemType; /* QElemType类型根据实际情况而定,这里假设为int */
    
    typedef struct QNode    /* 结点结构 */
    {
        QElemType data;
        struct QNode * next;
    }QNode,*QueuePtr;
    
    typedef struct            /* 队列的链表结构 */
    {
        //队头指针指向头节点,并不存放具体元素,哪怕队列为空,也有一个队头指针
        QueuePtr front;
        //队尾指针指向队尾元素本身
        QueuePtr rear;
    
    }LinkQueue;
    
    Status visit(QElemType c)
    {
        printf("%d ",c);
    }
    
    
    /* 构造一个空队列Q */
    Status InitQueue(LinkQueue *Q)
    { 
        QueuePtr node=(QueuePtr)malloc(sizeof(QNode));
        node->next=NULL;
        Q->rear=Q->front=node;
        return OK;
    }
    
    /* 销毁队列Q */
    Status DestroyQueue(LinkQueue *Q)
    {
        QueuePtr p=Q->front;
        QueuePtr q=NULL;
        while(p){
            q=p->next;
            free(p);
            p=q;
        }
        return OK;
    }
    
    /* 将Q清为空队列 */
    Status ClearQueue(LinkQueue *Q)
    {
        //只是蒋数据清空,但是保留头指针,也就是队头
        QueuePtr p=Q->front->next;
        QueuePtr q=NULL;
        while(p){
            q=p->next;
            free(p);
            p=q;
        }
        Q->front->next=NULL;
        Q->rear=Q->front;
    
    }
    
    /* 若Q为空队列,则返回TRUE,否则返回FALSE */
    Status QueueEmpty(LinkQueue Q)
    { 
        if(Q.rear==Q.front){
            return TRUE;
        }else{
            return FALSE;
        }
    }
    
    /* 求队列的长度 */
    int QueueLength(LinkQueue Q)
    { 
        int i=0;
        QueuePtr q=Q.front;
        while(q!=Q.rear){
        i++;
        q=q->next;
        }
        return i;
    }
    
    /* 若队列不空,则用e返回Q的队头元素,并返回OK,否则返回ERROR */
    Status GetHead(LinkQueue Q,QElemType *e)
    { 
        if(QueueEmpty(Q)){
            return ERROR;
        }
        *e=Q.front->next->data;
        return OK;
    }
    
    
    /* 插入元素e为Q的新的队尾元素 */
    Status EnQueue(LinkQueue *Q,QElemType e)
    { 
        QueuePtr node=(QueuePtr)malloc(sizeof(QNode));
        node->data=e;
        node->next=NULL;
        Q->rear->next=node;
        Q->rear=node;
        return OK;
    
    }
    
    /* 若队列不空,删除Q的队头元素,用e返回其值,并返回OK,否则返回ERROR */
    Status DeQueue(LinkQueue *Q,QElemType *e)
    {
        if(QueueEmpty(*Q)){
            return ERROR;
        }
        //删除的不是头指针,头指针并不放元素,而是头指针的下一个元素
        QueuePtr p=Q->front->next;
        *e=p->data;
        Q->front->next=p->next;
        //如果要删除的恰好就是尾元素,蒋队列重新置为初始状态
        if(p==Q->rear){
        Q->rear=Q->front;
        Q->front->next=NULL;
        }
        free(p);
        p=NULL;
    }
    
    /* 从队头到队尾依次对队列Q中每个元素输出 */
    Status QueueTraverse(LinkQueue Q)
    {
        QueuePtr q;
        q=Q.front->next;
        while(q){
            visit(q->data);
            q=q->next;
        }
        printf("
    ");
    }
    
    int main()
    {
        int i;
        QElemType d;
        LinkQueue q;
        i=InitQueue(&q);
        if(i)
            printf("成功地构造了一个空队列!
    ");
        printf("是否空队列?%d(1:空 0:否)  ",QueueEmpty(q));
        printf("队列的长度为%d
    ",QueueLength(q));
        EnQueue(&q,-5);
        EnQueue(&q,5);
        EnQueue(&q,10);
        printf("插入3个元素(-5,5,10)后,队列的长度为%d
    ",QueueLength(q));
        printf("是否空队列?%d(1:空 0:否)  ",QueueEmpty(q));
        printf("队列的元素依次为:");
        QueueTraverse(q);
        i=GetHead(q,&d);
        if(i==OK)
         printf("队头元素是:%d
    ",d);
        DeQueue(&q,&d);
        printf("删除了队头元素%d
    ",d);
        i=GetHead(q,&d);
        if(i==OK)
            printf("新的队头元素是:%d
    ",d);
        ClearQueue(&q);
        printf("清空队列后,q.front=%u q.rear=%u q.front->next=%u
    ",q.front,q.rear,q.front->next);
        DestroyQueue(&q);
        printf("销毁队列后,q.front=%u q.rear=%u
    ",q.front, q.rear);
        
        return 0;
    }
    链队列的实现

     1,队列所在链表的头指针不放置元素,也就是包含头节点

    2,队列的front指针即为链表的头指针,即队头部元素的前一个

    3,队列的rear指针指向尾元素本身

    4,队列为空的标志为:q->front=q->rear。因此清空队列的时候,对于最后一个元素需要额外判断。

    5,注意队列的初始化,销毁和置空的区别。

    二叉树

     二叉树具有以下性质:

    1.深度为k的二叉树至多有2的k次方-1个节点

    2.第k层之多有2的(k-1)个元素

    3.n0=n2+1

    4,具有n个节点的完全二叉树的深度为(log2(n)+1)

    5,对于完全二叉树,如果从0开始编号,那么i的根节点为i/2;左孩子为2i+1,右孩子为2i+2

    #include "stdio.h"    
    #include "stdlib.h"   
    #include <math.h>  
    #include "time.h"
    
    #define OK 1
    #define ERROR 0
    #define TRUE 1
    #define FALSE 0
    
    #define MAXSIZE 100 /* 存储空间初始分配量 */
    #define MAX_TREE_SIZE 100 /* 二叉树的最大结点数 */
    
    typedef int Status;        /* Status是函数的类型,其值是函数结果状态代码,如OK等 */
    typedef int TElemType;  /* 树结点的数据类型,目前暂定为整型 */
    TElemType Nil=0;
    typedef TElemType SqBiTree[MAX_TREE_SIZE]; /* 0号单元存储根结点  */
    
    typedef struct
    {
        int level;
        int order;
    }Position;
    
    
    Status visit(TElemType c)
    {
        printf("%d ",c);
        return OK;
    }
    
    /* 构造空二叉树T。因为T是固定数组,不会改变,故不需要& */
    Status InitBiTree(SqBiTree T)
    {
        int i;
        for(i=0;i<MAXSIZE;i++){
            T[i]=Nil;
        }
        return OK;
    }
    Status CreateBiTree(SqBiTree T){
        //注意双亲节点不能为空
        int i;
        for(i=0;i<=10;i++){
            T[i]=i+1;
            if(T[i]!=Nil&&T[(int)(i-1)/2]==Nil){
                printf("双亲节点不能为空!");
                exit(ERROR);
            }
        }
    
        for(i=11;i<MAXSIZE;i++){
            T[i]=Nil;
        }
        return OK;
    
    }
    
    Status BiTreeEmpty(SqBiTree T){
        //如果根节点为空,那么整个树为空
        if(T[0]==Nil){
            return TRUE;
        }else{
            return FALSE;
        }
    }
    //计算二叉树的深度也就是有多少层
    int BiTreeDepth(SqBiTree T)
    { 
        if(BiTreeEmpty(T)){
            return 0;
        }
        int i;
        for(i=MAXSIZE-1;i>=0;i--){
            if(T[i]!=Nil){
                break;
            }
        }
        return (int)(log(i)/log(2));
    }
    
    /* 初始条件: 二叉树T存在 */
    /* 操作结果:  当T不空,用e返回T的根,返回OK;否则返回ERROR,e无定义 */
    Status Root(SqBiTree T,TElemType *e)
    { 
        if(BiTreeEmpty(T)){
            return ERROR;
        }    
        *e=T[0];
        return OK;
    }
    
    /* 初始条件: 二叉树T存在,e是T中某个结点(的位置) */
    /* 操作结果: 返回处于位置e(层,本层序号)的结点的值 */
    TElemType Value(SqBiTree T,Position e)
    { 
        if(BiTreeEmpty(T)){
            return ERROR;
        }
    
        return T[(int)pow(2,e.level-1)+e.order-2];
    }
    
    /* 初始条件: 二叉树T存在,e是T中某个结点(的位置) */
    /* 操作结果: 给处于位置e(层,本层序号)的结点赋新值value */
    Status Assign(SqBiTree T,Position e,TElemType value)
    { 
        if(BiTreeEmpty(T)){
            return ERROR;
        }
        int index=(int)pow(2,e.level-1)+e.order-2;
        if(value!=Nil&&T[(index-1)/2]==Nil){
            return ERROR;
        }
        if(value==Nil&&(T[index*2+1]!=Nil||T[index*2+2]!=Nil)){
            return ERROR;
        }
        T[index]=value;
        return OK;
    }
    Status PreTraverse(SqBiTree T,int e){
        visit(T[e]);
        if(T[2*e+1]!=Nil){
            PreTraverse(T,2*e+1);
        }
        if(T[2*e+2]!=Nil){
            PreTraverse(T,2*e+2);
        }
    
    }
    Status PreOrderTraverse(SqBiTree T)
    { 
        if(!BiTreeEmpty(T)){
            PreTraverse(T,0);
        }
        printf("
    ");
        return OK;
    }
    
    /* InOrderTraverse()调用 */
    void InTraverse(SqBiTree T,int e)
    {     if(T[2*e+1]!=Nil){
            InTraverse(T,2*e+1);
        }
        visit(T[e]);
        if(T[2*e+2]!=Nil){
            InTraverse(T,2*e+2);
        }
    }
    
    /* 初始条件: 二叉树存在 */
    /* 操作结果: 中序遍历T。 */
    Status InOrderTraverse(SqBiTree T)
    {     
        if(!BiTreeEmpty(T)){
            InTraverse(T,0);
        }
        printf("
    ");
        return OK;
    }
    
    /* PostOrderTraverse()调用 */
    void PostTraverse(SqBiTree T,int e)
    { 
        if(T[2*e+1]!=Nil){
            PostTraverse(T,2*e+1);
        }
        if(T[2*e+2]!=Nil){
            PostTraverse(T,2*e+2);
        }
        visit(T[e]);
    }
    
    /* 初始条件: 二叉树T存在 */
    /* 操作结果: 后序遍历T。 */
    Status PostOrderTraverse(SqBiTree T)
    { 
        if(!BiTreeEmpty(T)){
            PostTraverse(T,0);
        }
        return OK;
    }
    
    /* 层序遍历二叉树 */
    void LevelOrderTraverse(SqBiTree T)
    { 
        //按照下标的顺序遍历即可
        int j;
        for(j=MAX_TREE_SIZE-1;T[j]==Nil;j--);
        int i;
        for(i=0;i<=j;i++){
            visit(T[i]);
        }
        printf("
    ");
            
        
    }
    
    /* 逐层、按本层序号输出二叉树 */
    void Print(SqBiTree T)
    { 
        int i,j,k;
        Position p;
        TElemType e;
        for(j=1;j<=BiTreeDepth(T);j++){
            printf("第%d层:",j);
            for(k=1;k<=pow(2,j-1);k++){
                e=Value(T,p);
                printf("第%d个:%d,",k,e);
            }
            printf("
    ");
        }
    }
    
    Status ClearBiTree(SqBiTree T){
        int i;
        for(i=0;i<MAX_TREE_SIZE;i++){
            T[i]=Nil;
        }
        return OK;
    
    }
    
    int main()
    {
        Status i;
        Position p;
        TElemType e;
        SqBiTree T;
        InitBiTree(T);
        CreateBiTree(T);
        printf("建立二叉树后,树空否?%d(1:是 0:否) 树的深度=%d
    ",BiTreeEmpty(T),BiTreeDepth(T));
        i=Root(T,&e);
        if(i)
            printf("二叉树的根为:%d
    ",e);
        else
            printf("树空,无根
    ");
        printf("层序遍历二叉树:
    ");
        LevelOrderTraverse(T);
        printf("前序遍历二叉树:
    ");
        PreOrderTraverse(T);
        printf("中序遍历二叉树:
    ");
        InOrderTraverse(T);
        printf("后序遍历二叉树:
    ");
        PostOrderTraverse(T);
        printf("修改结点的层号3本层序号2。");
        p.level=3;
        p.order=2;
        e=Value(T,p);
        printf("待修改结点的原值为%d请输入新值:50 ",e);
        e=50;
        Assign(T,p,e);
        printf("前序遍历二叉树:
    ");
        PreOrderTraverse(T);
        ClearBiTree(T);
        printf("清除二叉树后,树空否?%d(1:是 0:否) 树的深度=%d
    ",BiTreeEmpty(T),BiTreeDepth(T));
        i=Root(T,&e);
        if(i)
            printf("二叉树的根为:%d
    ",e);
        else
            printf("树空,无根
    ");
        
        return 0;
    }
    二叉树的顺序实现

    1)顺序实现中就是利用下标来代表父母节点、子节点、兄弟节点之间的关系。以及二叉树的性质和坐标之间的关系罢了。

    2)在赋值时需要注意一条约束,如果子节点不为空,那么父母节点一定不能为空。

    3)重点关注先序、中序、后序遍历的实现。

    #include "string.h"
    #include "stdio.h"    
    #include "stdlib.h"   
    #include "math.h"  
    #include "time.h"
    
    #define OK 1
    #define ERROR 0
    #define TRUE 1
    #define FALSE 0
    
    #define MAXSIZE 100 /* 存储空间初始分配量 */
    
    typedef int Status;        /* Status是函数的类型,其值是函数结果状态代码,如OK等 */
    /* 用于构造二叉树********************************** */
    typedef char String[24]; /*  0号单元存放串的长度 */
    String str;
    
    Status StrAssign(String T,char *chars)
    { 
        int i;
        if(strlen(chars)>MAXSIZE){
            return ERROR;
        }
        T[0]=strlen(chars);
        for(i=1;i<=T[0];i++){
            T[i]=*(chars+i-1);
        }
        return OK;
    }
    /* ************************************************ */
    
    typedef char TElemType;
    TElemType Nil=' '; /* 字符型以空格符为空 */
    
    Status visit(TElemType e)
    {    
        printf("%c ",e);
        return OK;
    }
    //采用左右孩子表示方法
    typedef struct BiTNode  /* 结点结构 */
    {
        TElemType data;
        struct BiTNode *lchild,*rchild;
    }BiTNode,*BiTree;
    
    
    /* 构造空二叉树T */
    Status InitBiTree(BiTree *T)
    { 
        (*T)=NULL;
        return;
    }
    
    /* 初始条件: 二叉树T存在。操作结果: 销毁二叉树T */
    //利用递归的方法进行销毁
    void DestroyBiTree(BiTree *T)
    { 
        if(!(*T)){
            return;
        }
        if((*T)->lchild){
            DestroyBiTree(&((*T)->lchild));
        }
        if((*T)->rchild){
            DestroyBiTree(&((*T)->rchild));
        }
        free(*T);
        *T=NULL;
    }
    
    int myIndex=1;
    /* 按前序输入二叉树中结点的值(一个字符) */
    /* #表示空树,构造二叉链表表示二叉树T。 */
    void CreateBiTree(BiTree *T)
    { 
        TElemType ch;
        ch=str[myIndex++];
        if(ch=='#'){
            *T=NULL;
        }else{
            (*T)=(BiTNode*)malloc(sizeof(BiTNode));
            if(!(*T)){
                exit(OVERFLOW);
            }
            (*T)->data=ch;
            CreateBiTree(&((*T)->lchild));
            CreateBiTree(&((*T)->rchild));
        }
    
    
    
    }
    
    /* 初始条件: 二叉树T存在 */
    /* 操作结果: 若T为空二叉树,则返回TRUE,否则FALSE */
    Status BiTreeEmpty(BiTree T)
    { 
        if(T)
            return FALSE;
        else
            return TRUE;
    }
    
    #define ClearBiTree DestroyBiTree
    
    /* 初始条件: 二叉树T存在。操作结果: 返回T的深度 */
    int BiTreeDepth(BiTree T)
    {
        int i,j;
        if(!T){
            return 0;
        }
    
        if(T->lchild){
            i=BiTreeDepth(T->lchild);
        }else{
            i=0;
        }
        if(T->rchild){
            j=BiTreeDepth(T->rchild);
        }else{
            j=0;
        }
    //    printf("%d %d
    ",i,j);
        return i>j?i+1:j+1;
    }
    
    /* 初始条件: 二叉树T存在。操作结果: 返回T的根 */
    TElemType Root(BiTree T)
    { 
        if(BiTreeEmpty(T)){
            return Nil;
        }
        return T->data;
    }
    
    /* 初始条件: 二叉树T存在,p指向T中某个结点 */
    /* 操作结果: 返回p所指结点的值 */
    TElemType Value(BiTree p)
    {
        return p->data;
    }
    
    /* 给p所指结点赋值为value */
    void Assign(BiTree p,TElemType value)
    {
        p->data=value;
    }
    
    /* 初始条件: 二叉树T存在 */
    /* 操作结果: 前序递归遍历T */
    void PreOrderTraverse(BiTree T)
    { 
        if(T==NULL){
            return;
        }
        visit(T->data);
        if(T->lchild){
            PreOrderTraverse(T->lchild);
        }
        if(T->rchild){
            PreOrderTraverse(T->rchild);
        }
    }
    
    /* 初始条件: 二叉树T存在 */
    /* 操作结果: 中序递归遍历T */
    void InOrderTraverse(BiTree T)
    { 
        if(!T){
            return ;
        }
        if(T->lchild){
            InOrderTraverse(T->lchild);
        }
        visit(T->data);
        if(T->rchild){
            InOrderTraverse(T->rchild);
        }
    }
    
    /* 初始条件: 二叉树T存在 */
    /* 操作结果: 后序递归遍历T */
    void PostOrderTraverse(BiTree T)
    {
        if(!T){
            return;
        }
        if(T->lchild){
            PostOrderTraverse(T->lchild);
        }
        if(T->rchild){
            PostOrderTraverse(T->rchild);
        }
        visit(T->data);
    }
    
    
    int main()
    {
        int i;
        BiTree T;
        TElemType e1;
        InitBiTree(&T);
    
        
        StrAssign(str,"ABDH#K###E##CFI###G#J##");
    
        CreateBiTree(&T);
    
        printf("构造空二叉树后,树空否?%d(1:是 0:否) 树的深度=%d
    ",BiTreeEmpty(T),BiTreeDepth(T));
        e1=Root(T);
        printf("二叉树的根为: %c
    ",e1);
    
        printf("
    前序遍历二叉树:");
        PreOrderTraverse(T);
        printf("
    中序遍历二叉树:");
        InOrderTraverse(T);
        printf("
    后序遍历二叉树:");
        PostOrderTraverse(T);
        ClearBiTree(&T);
        printf("
    清除二叉树后,树空否?%d(1:是 0:否) 树的深度=%d
    ",BiTreeEmpty(T),BiTreeDepth(T));
        i=Root(T);
        if(!i)
            printf("树空,无根
    ");
        
        return 0;
    }
    二叉树链式实现

    1)空指针、指针变量为空、指向指针的指针这其中有些概念还是不清楚。

    2)二叉树的销毁、创建、求树深、遍历都是采用递归方法,注意递归的原理和。

    关于二叉树的经典题目;

    1)判定两颗二叉树是否相等

    bool bitreeEqual(Node* node1,Node* node2){
        if(node1==NULL&&node2==NULL){
            return true;
        }   
        if(node1!=NULL||node2!=NULL){
            return false;
        }   
        if(node1->data==node2->data){
            return bitreeEqual(node1->left,node2->left)&&bitreeEqual(node1->right,node2->right);
        }   
    
    }
    判断两二叉树是否相等

    2)如果二叉树的左右节点可以旋转,判断其是否相等

    思路同上道题,最后的判定条件修改即可

    3)计算二叉树的高度

    //计算二叉树的深度
    int bitreeDepth(Node* node){
        if(node==NULL){
            return 0;
        }
        int lDepth=bitreeDepth(node->left)+1;
        int rDepth=bitreeDepth(node->right)+1;
        return lDepth>rDepth?lDepth:rDepth;
    }
    计算二叉树的高度

    4)计算二叉树两个节点间的最大路径长度

    5)判断一棵树是不是二叉查找树

    bool isSearchTree(Node* node){
        if(node==NULL){
            return true;
        }   
    
        if(node->left==NULL&&node->right==NULL){
            return true;
        }   
    
        if(node->left==NULL&&node->right!=NULL){
            if(node->right->data>=node->data){
                return isSearchTree(node->right);
            }else{
                return false;
            }   
        }   
    
        if(node->right==NULL&&node->left!=NULL){
            if(node->left->data<=node->data){
                return isSearchTree(node->left);
            }else{
                return false;
            }
        }
    判断一棵树是否是二叉查找树

    思路二:二叉查找树的中序遍历是递增序列,也可以从这个角度出发

    6) 判断一棵树是不是AVL树

    7)AVL树木的插入和删除

    以上都是采用递归的思路解决:书写递归是的一些总结:

    1)首先构造递归到终点的极限情况,如节点为空,下标超范等

    2)其次是先序,后序还是中序,具体问题具体分析

    3)上一次的递归结果,作为这一次的条件依赖(比如两棵树是否相等)还是输入(比如计算树的高度),具体问题具体分析

    4)递归之间传递参数,可以有的方法是:1)返回值;2)参数(递归函数内部定义局部变量,并将该局部变量作为递归函数的形参);3)全局变量;4)函数形参(外部定义一个变量,并将该变量作为递归函数的形参传入),这种方式在很多情况也可以用方法2)来解决;

  • 相关阅读:
    PHP按权重随机
    PHP将汉字转为拼音
    php支持解密的加密算法示例
    小波变换检测信号突变点的MATLAB实现
    OFDM通信系统的MATLAB仿真(2)
    OFDM通信系统的MATLAB仿真(1)
    java.lang.reflect.Constructor.getParameterTypes()方法示例
    createQuery 与 createNativeQuery 区别
    java.lang.StringBuilder.deleteCharAt()方法实例
    String.format()详细用法
  • 原文地址:https://www.cnblogs.com/bobodeboke/p/3581231.html
Copyright © 2011-2022 走看看