数据结构回顾

关于指针的一点知识

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

这种情况下的解决方法有两种: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("\n");
    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\n",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 \n",ListLength(L));
    i=ListEmpty(L);
    printf("L是否空:i=%d(1:是 0:否)\n",i);

    i=ClearList(&L);
    printf("清空L后:ListLength(L)=%d\n",ListLength(L));
    i=ListEmpty(L);
    printf("L是否空:i=%d(1:是 0:否)\n",i);

    for(j=1;j<=10;j++)
            ListInsert(&L,j,j);
    printf("在L的表尾依次插入1~10后:L.data=");
    ListTraverse(L); 

    printf("ListLength(L)=%d \n",ListLength(L));

    ListInsert(&L,1,0);
    printf("在L的表头插入0后:L.data=");
    ListTraverse(L); 
    printf("ListLength(L)=%d \n",ListLength(L));

    GetElem(L,5,&e);
    printf("第5个元素的值为:%d\n",e);
    for(j=3;j<=4;j++)
    {
            k=LocateElem(L,j);
            if(k)
                    printf("第%d个元素的值为%d\n",k,j);
            else
                    printf("没有值为%d的元素\n",j);
    }
    

    k=ListLength(L); /* k为表长 */
    for(j=k+1;j>=k;j--)
    {
            i=ListDelete(&L,j,&e); /* 删除第j个数据 */
            if(i==ERROR)
                    printf("删除第%d个数据失败\n",j);
            else
                    printf("删除第%d个的元素值为:%d\n",j,e);
    }
    printf("依次输出L的元素:");
    ListTraverse(L); 

    j=5;
    ListDelete(&L,j,&e); /* 删除第5个数据 */
    printf("删除第%d个的元素值为:%d\n",j,e);

    printf("依次输出L的元素:");
    ListTraverse(L); 

    i=ClearList(&L);
    printf("\n清空L后:ListLength(L)=%d\n",ListLength(L));
    CreateListHead(&L,20);
    printf("整体创建L的元素(头插法):");
    ListTraverse(L); 
    
    i=ClearList(&L);
    printf("\n删除L后:ListLength(L)=%d\n",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("\n");
    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\n",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 \n",ListLength(L));
    ListReverse(&L);
    printf("链表逆序之后,ListLength(L)=%d; \nL.data=",ListLength(L));
   ListTraverse(L);
    i=ListEmpty(L);
    printf("L是否空:i=%d(1:是 0:否)\n",i);

    i=ClearList(&L);
    printf("清空L后:ListLength(L)=%d\n",ListLength(L));
    i=ListEmpty(L);
    printf("L是否空:i=%d(1:是 0:否)\n",i);

    for(j=1;j<=10;j++)
            ListInsert(&L,j,j);
    printf("在L的表尾依次插入1~10后:L.data=");
    ListTraverse(L); 

    printf("ListLength(L)=%d \n",ListLength(L));

    ListInsert(&L,1,0);
    printf("在L的表头插入0后:L.data=");
    ListTraverse(L); 
    printf("ListLength(L)=%d \n",ListLength(L));

    GetElem(L,5,&e);
    printf("第5个元素的值为:%d\n",e);
    for(j=3;j<=4;j++)
    {
            k=LocateElem(L,j);
            if(k)
                    printf("第%d个元素的值为%d\n",k,j);
            else
                    printf("没有值为%d的元素\n",j);
    }
    

    k=ListLength(L); /* k为表长 */
    for(j=k+1;j>=k;j--)
    {
            i=ListDelete(&L,j,&e); /* 删除第j个数据 */
            if(i==ERROR)
                    printf("删除第%d个数据失败\n",j);
            else
                    printf("删除第%d个的元素值为:%d\n",j,e);
    }
    printf("依次输出L的元素:");
    ListTraverse(L); 

    j=5;
    ListDelete(&L,j,&e); /* 删除第5个数据 */
    printf("删除第%d个的元素值为:%d\n",j,e);

    printf("依次输出L的元素:");
    ListTraverse(L); 

    i=ClearList(&L);
    printf("\n清空L后:ListLength(L)=%d\n",ListLength(L));
    CreateListHead(&L,20);
    printf("整体创建L的元素(头插法):");
    ListTraverse(L); 
    
    i=ClearList(&L);
    printf("\n删除L后:ListLength(L)=%d\n",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("\n");
    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\n",e);
        printf("栈空否:%d(1:空 0:否)\n",StackEmpty(s));
        GetTop(s,&e);
        printf("栈顶元素 e=%d 栈的长度为%d\n",e,StackLength(s));
        ClearStack(&s);
        printf("清空栈后,栈空否:%d(1:空 0:否)\n",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("\n");
    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\n",e);
        printf("栈空否:%d(1:空 0:否)\n",StackEmpty(s));
        GetTop(s,&e);
        printf("栈顶元素 e=%d 栈的长度为%d\n",e,StackLength(s));
        ClearStack(&s);
        printf("清空栈后,栈空否:%d(1:空 0:否)\n",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:否)\n",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\n",QueueLength(Q));
    printf("现在队列空否?%u(1:空 0:否)\n",QueueEmpty(Q));
    printf("连续%d次由队头删除元素,队尾插入元素:\n",MAXSIZE);
    for(l=1;l<=MAXSIZE;l++)
    {
        DeQueue(&Q,&d);
        printf("删除的元素是%d,插入的元素:%d \n",d,l+1000);
        /* scanf("%d",&d); */
        d=l+1000;
        EnQueue(&Q,d);
    }
    l=QueueLength(Q);

    printf("现在队列中的元素为: \n");
    QueueTraverse(Q);
    printf("共向队尾插入了%d个元素\n",i+MAXSIZE);
    if(l-2>0)
        printf("现在由队头删除%d个元素:\n",l-2);
    while(QueueLength(Q)>2)
    {
        DeQueue(&Q,&d);
        printf("删除的元素值为%d\n",d);
    }

    j=GetHead(Q,&d);
    if(j)
        printf("现在队头元素为: %d\n",d);
    ClearQueue(&Q);
    printf("清空队列后, 队列空否?%u(1:空 0:否)\n",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("\n");
}

int main()
{
    int i;
    QElemType d;
    LinkQueue q;
    i=InitQueue(&q);
    if(i)
        printf("成功地构造了一个空队列!\n");
    printf("是否空队列?%d(1:空 0:否)  ",QueueEmpty(q));
    printf("队列的长度为%d\n",QueueLength(q));
    EnQueue(&q,-5);
    EnQueue(&q,5);
    EnQueue(&q,10);
    printf("插入3个元素(-5,5,10)后,队列的长度为%d\n",QueueLength(q));
    printf("是否空队列?%d(1:空 0:否)  ",QueueEmpty(q));
    printf("队列的元素依次为:");
    QueueTraverse(q);
    i=GetHead(q,&d);
    if(i==OK)
     printf("队头元素是:%d\n",d);
    DeQueue(&q,&d);
    printf("删除了队头元素%d\n",d);
    i=GetHead(q,&d);
    if(i==OK)
        printf("新的队头元素是:%d\n",d);
    ClearQueue(&q);
    printf("清空队列后,q.front=%u q.rear=%u q.front->next=%u\n",q.front,q.rear,q.front->next);
    DestroyQueue(&q);
    printf("销毁队列后,q.front=%u q.rear=%u\n",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("\n");
    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("\n");
    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("\n");
        
    
}

/* 逐层、按本层序号输出二叉树 */
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("\n");
    }
}

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\n",BiTreeEmpty(T),BiTreeDepth(T));
    i=Root(T,&e);
    if(i)
        printf("二叉树的根为:%d\n",e);
    else
        printf("树空,无根\n");
    printf("层序遍历二叉树:\n");
    LevelOrderTraverse(T);
    printf("前序遍历二叉树:\n");
    PreOrderTraverse(T);
    printf("中序遍历二叉树:\n");
    InOrderTraverse(T);
    printf("后序遍历二叉树:\n");
    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("前序遍历二叉树:\n");
    PreOrderTraverse(T);
    ClearBiTree(T);
    printf("清除二叉树后,树空否?%d(1:是 0:否) 树的深度=%d\n",BiTreeEmpty(T),BiTreeDepth(T));
    i=Root(T,&e);
    if(i)
        printf("二叉树的根为:%d\n",e);
    else
        printf("树空,无根\n");
    
    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\n",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\n",BiTreeEmpty(T),BiTreeDepth(T));
    e1=Root(T);
    printf("二叉树的根为: %c\n",e1);

    printf("\n前序遍历二叉树:");
    PreOrderTraverse(T);
    printf("\n中序遍历二叉树:");
    InOrderTraverse(T);
    printf("\n后序遍历二叉树:");
    PostOrderTraverse(T);
    ClearBiTree(&T);
    printf("\n清除二叉树后,树空否?%d(1:是 0:否) 树的深度=%d\n",BiTreeEmpty(T),BiTreeDepth(T));
    i=Root(T);
    if(!i)
        printf("树空,无根\n");
    
    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)来解决;

 

posted @ 2014-03-04 21:39  bobo的学习笔记  阅读(707)  评论(0编辑  收藏  举报