二叉排序树C语言实现(超级详细代码)

 今天来给大家讲解一下二叉排序树C语言代码实现

 

 

二叉排序树C语言实现(超级详细代码)_第1张图片

 



typedef int ElemType;     // 自定义数据元素为整数。

// 二叉树的数据结构。
typedef struct BSTNode
{
    ElemType   data;           // 存放结点的数据元素。
    struct BSTNode* lchild;    // 指向左子结点地址的指针。
    struct BSTNode* rchild;    // 指向右子结点地址的指针。
}BSTNode, * BSTree;
///

// 在树TT中插入关键字为ee的新结点(递归实现),返回值:0-树中已存在关键字为ee的结点;1-成功。
int Insert(BSTree* TT, ElemType* ee);
// 在树TT中插入关键字为ee的新结点(非递归实现),返回值:0-树中已存在关键字为ee的结点;1-成功。
int Insert1(BSTree* TT, ElemType* ee);

// 用数组arr中的序列构建二叉排序树TT。
// 以下两种写法都可以。
//void CreateBST(BSTree *TT,int arr[],int len);
void CreateBST(BSTree* TT, int* arr, int len);

// 在树TT中查找值为ee的结点(递归实现),成功返回结点的地址,失败返回NULL。
BSTNode* Find(BSTree TT, ElemType* ee);
// 在树TT中查找值为ee的结点(非递归实现),成功返回结点的地址,失败返回NULL。
BSTNode* Find1(BSTree TT, ElemType* ee);

// 在树TT中删除值为ee的结点,成功返回0,结点不存在返回1。
int Delete(BSTree* TT, ElemType* ee);

// 求二叉树的高度。
int TreeDepth(BSTree TT);

// 访问结点元素。
void visit(BSTNode* pp);

// 采用递归的方法对二叉树的先序遍历。
void PreOrder(BSTree TT);

// 采用递归的方法对二叉树的中序遍历。
void InOrder(BSTree TT);

// 采用递归的方法对二叉树的后序遍历。
void PostOrder(BSTree TT);

int main()
{
    BSTree TT = 0; // 声明树指针变量。

    ElemType arr[] = { 50,66,60,26,21,30,70,68 };

    /*
    // 用数组arr中的序列构建二叉排序树TT。
    // 构建的二叉排序树将如下:
                50
             /     \
            26      66
           /  \    /  \
          21  30 60   70
                     /
                    68
    */
    CreateBST(&TT, arr, sizeof(arr) / sizeof(ElemType));

    ElemType ee;

    // 在树TT中查找值为ee的结点,成功返回结点的地址,失败返回NULL。
    ee = 30;
    BSTNode* ss = Find(TT, &ee);
    if (ss != NULL) printf("查找成功,结点的地址是%p,值是%d。\n", ss, ss->data);
    else printf("查找失败。\n");

    // 二叉树的中序遍历。
    printf("中序遍历结果1:"); InOrder(TT); printf("\n");

    // 在树TT中删除值为ee的结点,成功返回0,结点不存在返回1。
    ee = 50;
    printf("从树中删除值为ee的结点,Delete()的返回值是%d。\n", Delete(&TT, &ee));

    // 二叉树的中序遍历。
    printf("中序遍历结果2:"); InOrder(TT); printf("\n");

    return 0;
}

// 二叉树的先序遍历。
void PreOrder(BSTree TT)
{
    if (TT == NULL) return;

    visit(TT);               // 访问子树TT的根结点。
    PreOrder(TT->lchild);    // 遍历左子树。
    PreOrder(TT->rchild);    // 遍历右子树。
}

// 二叉树的中序遍历。
void InOrder(BSTree TT)
{
    if (TT == NULL) return;

    InOrder(TT->lchild);     // 遍历左子树。
    visit(TT);               // 访问子树TT的根结点。
    InOrder(TT->rchild);     // 遍历右子树。
}

// 二叉树的后序遍历。
void PostOrder(BSTree TT)
{
    if (TT == NULL) return;

    PostOrder(TT->lchild);     // 遍历左子树。
    PostOrder(TT->rchild);     // 遍历右子树。
    visit(TT);                 // 访问子树TT的根结点。
}

// 求二叉树的高度。
int TreeDepth(BSTree TT)
{
    if (TT == NULL) return 0;

    int ll = TreeDepth(TT->lchild);  // 求左子树的高度。

    int rr = TreeDepth(TT->rchild);  // 求右子树的高度。

    return ll > rr ? ll + 1 : rr + 1;     // 取左、右子树的较大者再加上根结点的高度。
}

// 访问结点元素。
void visit(BSTNode* pp)
{
    printf("%d ", pp->data);  // 访问结点元素就是把值输出来,意思一下就行了。
}

// 在树TT中插入关键字为ee的新结点(递归实现),返回值:0-树中已存在关键字为ee的结点;1-成功。
int Insert(BSTree* TT, ElemType* ee)
{
    // 如果当前子树为空,创建子树的根结点。
    if ((*TT) == NULL)
    {
        (*TT) = (BSTree)malloc(sizeof(BSTNode));
        memcpy(&(*TT)->data, ee, sizeof(ElemType));  // 考虑数据元素ee为结构体的情况,采用memcpy而不是直接赋值。
        (*TT)->lchild = (*TT)->rchild = NULL;  // 当前子树的左右孩子指针置空。
        return 1;  // 返回成功。
    }

    if (*ee == (*TT)->data) return 0; // 如果ee已存在,返回失败。

    if (*ee < (*TT)->data) Insert(&(*TT)->lchild, ee);  // 递归向左插入。
    else Insert(&(*TT)->rchild, ee);  // 递归向右插入。
}

// 在树TT中插入关键字为ee的新结点(非递归实现),返回值:0-树中已存在关键字为ee的结点;1-成功。
int Insert1(BSTree* TT, ElemType* ee)
{
    // 如果树为空,创建树的根结点。
    if ((*TT) == NULL)
    {
        (*TT) = (BSTree)malloc(sizeof(BSTNode));
        memcpy(&(*TT)->data, ee, sizeof(ElemType));  // 考虑数据元素ee为结构体的情况,采用memcpy而不是直接赋值。
        (*TT)->lchild = (*TT)->rchild = NULL;  // 树的左右孩子指针置空。
        return 1;  // 返回成功。
    }

    BSTNode* pss = NULL;  // 记录双亲结点的地址。
    BSTNode* ss = (*TT);  // 用于查找的临时指针。
    int  rl = 0;          // 记录ss是双亲结点的左子树还是右子树,0-左子树;1-右子树。

    while (ss != NULL)
    {
        if (*ee == ss->data) return 0; // 如果ee已存在,返回失败。

        pss = ss;  // 记录双亲结点的地址。
        if (*ee < ss->data) { ss = ss->lchild; rl = 0; }  // 继续向左走。
        else { ss = ss->rchild; rl = 1; }  // 继续向右走。
    }

    // 分配新结点。
    ss = (BSTree)malloc(sizeof(BSTNode));
    memcpy(&ss->data, ee, sizeof(ElemType));  // 考虑数据元素ee为结构体的情况,采用memcpy而不是直接赋值。
    ss->lchild = ss->rchild = NULL;  // 当前子树的左右孩子指针置空。

    // 让双亲结点的左或右指针指向新分配的结点。
    if (rl == 0) pss->lchild = ss;
    else pss->rchild = ss;

    return 1;  // 返回成功。
}

// 用数组arr中的序列构建二叉排序树TT。
// 以下两种写法都可以。
//void CreateBST(BSTree *TT,int arr[],int len)
void CreateBST(BSTree* TT, int* arr, int len)
{
    (*TT) = NULL;

    int ii = 0;
    for (ii = 0; ii < len; ii++)
    {
        Insert(TT, &arr[ii]);  // 把数组中的元素逐个插入树中。
        // Insert1(TT,&arr[ii]);  // 把数组中的元素逐个插入树中。
    }
}

// 在树TT中查找值为ee的结点(递归实现),成功返回结点的地址,失败返回NULL。
BSTNode* Find(BSTree TT, ElemType* ee)
{
    if (TT == NULL) return NULL;    // 查找失败。

    if (*ee == TT->data) return TT;  // 查找成功。 

    if (*ee < TT->data) return Find(TT->lchild, ee); // 递归向左查找。
    else return Find(TT->rchild, ee);             // 递归向右查找。
}

// 在树TT中查找值为ee的结点(非递归实现),成功返回结点的地址,失败返回NULL。
BSTNode* Find1(BSTree TT, ElemType* ee)
{
    BSTNode* ss = TT;  // 用于查找的临时指针,也可以直接用TT。

    while (ss != NULL)
    {
        if (*ee == ss->data) return ss;  // 成功找到。

        if (*ee < ss->data) ss = ss->lchild;  // 继续向左走。
        else ss = ss->rchild;  // 继续向右走。
    }

    return NULL;

    /*
    // 以下代码更精简,可以取代以上的代码。
    while ( (TT!=NULL) && (*ee!=TT->data) )
    {
      if (*eedata) TT=TT->lchild;  // 继续向左走。
      else TT=TT->rchild;  // 继续向右走。
    }

    return TT;
    */
}

// 在树TT中删除值为ee的结点,成功返回0,结点不存在返回1。
int Delete(BSTree* TT, ElemType* ee)
{
    if ((*TT) == NULL) return 1; // 树为空,返回1。

    // 1)如果树只有根结点,并且待删除的结点就是根结点。
    if (((*TT)->data == *ee) && ((*TT)->lchild == NULL) && ((*TT)->rchild == NULL))
    {
        free(*TT); (*TT) = 0; return 0;
    }

    BSTNode* pss = NULL;  // 记录双亲结点的地址。
    BSTNode* ss = (*TT);  // 用于查找的临时指针。
    int  rl = 0;          // 记录ss是双亲结点的左子树还是右子树,0-左子树;1-右子树。

    // 查找待删除的结点。
    while (ss != NULL)
    {
        if (*ee == ss->data) break;  // 成功找到。

        pss = ss;  // 记录双亲结点的地址。
        if (*ee < ss->data) { ss = ss->lchild; rl = 0; }  // 继续向左走。
        else { ss = ss->rchild; rl = 1; }  // 继续向右走。
    }

    // 结点不存在,返回1。
    if (ss == NULL) return 1;

    // 2)如果待删除的结点ss是叶结点,直接删除,不会破坏二叉排序树的性质。
    if ((ss->lchild == NULL) && (ss->rchild == NULL))
    {
        free(ss);   // 释放结点。

        // 修改双亲结点pss的左或右指针指向NULL。
        if (rl == 0) pss->lchild = NULL;
        else pss->rchild = NULL;

        return 0;  // 返回成功。
    }

    // 3)如果待删除的结点ss只有左子树或右子树,则让子树代替自己。
    if ((ss->lchild == NULL) || (ss->rchild == NULL))
    {
        if (ss->lchild != NULL)  // 有左子树。
        {
            // 修改双亲结点pss的左或右指针指向ss的左子树。
            if (rl == 0) pss->lchild = ss->lchild;
            else pss->rchild = ss->lchild;
        }
        else  // 有右子树。
        {
            // 修改双亲结点pss的左或右指针指向ss的右子树。
            if (rl == 0) pss->lchild = ss->rchild;
            else pss->rchild = ss->rchild;
        }

        return 0;  // 返回成功。
    }

    // 4)如果待删除的结点ss有左子树和右子树,让左子树最右侧的结点代替自己,然后再删除左子树最右侧的结点。
    // 也可以让右子树最左侧的结点代替自己,然后删除右子树最左侧的结点。
    BSTNode* pss1 = ss;        // 记录双亲结点的地址。
    BSTNode* ss1 = ss->lchild; // 用于查找的临时指针。
    int  rl1 = 0;              // 记录ss1是双亲结点的左子树还是右子树,0-左子树;1-右子树。

    // 左子树向右走到尽头。
    while (ss1->rchild != NULL)
    {
        rl1 = 1; pss1 = ss1; ss1 = ss1->rchild;
    }

    // 把左子树最右侧的结点值复制到结点ss中。
   

    // 左子树最右侧的结点ss1必定无右子树。
    // 修改双亲结点pss1的左或右指针指向ss1的左子树,ss1的左子树可以为空。
    if (rl1 == 0) pss1->lchild = ss1->lchild;
    else pss1->rchild = ss1->lchild;

    free(ss1);  // 释放ss1。

    return 0;
}


//删除写法二:
//直接返回删除后的树
BSTree Delete2(BSTree TT, ElemType ee)
{
    BSTree f, p;
    //f指针记录待删除结点的双亲结点
    //p指针用来记录待删除结点
    f = NULL;
    p = TT;
    while (p)
    {
        if (p->data = ee)  break;
        f = p;
        if (p->data > ee)  p = p->lchild;
        else p = p->rchild;
    }

    //第一种情况p为NULL,即是没有待删除结点
    if (p == NULL) return TT;

    //分为两种情况,待删除结点有左子树和无左子树
    if (p->lchild == NULL) //无左子树
    {
        //对双亲结点进行三种讨论

        //第一种如果双亲结点是空
        if (f == NULL)  TT = p->rchild;

        //第二种p是f的左孩子
        else if (f->lchild == p)  f->lchild = p->rchild;

        //第三种p是f的右孩子

        else  f->rchild = p->rchild;

        free(p);

    }

    //找到以p为根节点左子树的最右边
    
    else
    {
       //m是n的双亲结点

       //m为p结点,n为p结点的左孩子
        BSTree m = p, n = p->lchild;

        //找到以p为根节点左子树的最右边
        while (n->rchild)
        {
            m = n;
            n = n->rchild;
        }
        
        //为两种情况,以n为根节点的树有无右子树

        if (p == m) m->lchild = n->lchild;

        else m->rchild = n->lchild;

        p->data = n->data;

        free(n);



    }
    return TT;


}

 

 

你可能感兴趣的:(c语言,数据结构,算法)