C Primer Plus--高級數據結構之二叉樹

C Primer Plus–高級數據結構表示之二叉樹

二叉搜索樹 Binary Search Tree

二叉樹是一種高級數據結構。樹中的每個節點都包含一個項目和兩個指向其他節點的指針。
每個節點都有兩個子節點:左節點、右節點。在左節點中的項目是父節點中項目的前序向,而在右節點中的項目是父節點項目的後序向。
二叉樹中每一個節點本身是其後代節點的根,此節點與其後代節點構成一個子樹,子樹有左右之分。

用C構建二叉樹ADT

首先明確二叉樹結構:

二叉樹或者是一個空的節點集合(空樹),或者是一個指定某個節點爲根的節點集合。每個節點有兩個作爲其後代的樹,稱爲左子樹和右子樹。
每個子樹本身又是一個二叉樹,也包含它是個空樹的可能性。
二叉搜索樹是有序的二叉樹,它的每個節點包含一個項目,它的所有左子樹的項目排在根項目的前面,而根項目排在所有右子樹項目的前面。

而且二叉樹的類型操作有:

  • 樹初始化爲空樹
  • 查詢樹是否爲空
  • 查詢樹是否已滿
  • 查詢樹中項目個數
  • 向樹中添加項目
  • 從樹中刪除項目
  • 從樹中搜索一個項目
  • 遍歷樹中所有項目
  • 清空樹

樹結構的定義

假設一個項目中包含一部電影的名字,上映年份,我們定義項目爲Item:定義節點Node結構,包含一部電影,節點的左子節點,節點的右子節點指針;定義結構Tree包含根節點指針、樹的項目個數。

#define TITLE_MAX_CHARS 40

typedef struct movie {
    char title[TITLE_MAX_CHARS];
    int year;
} Item;

typedef struct node {
    Item movie;
    struct movie * left;
    struct movie * right;
} Node;

typedef struct tree {
    Node * root;
    int size;
} Tree;

定義好了數據結構,下面進行樹操作的定義:

//初始化樹
void InitializeTree(Tree * ptoTree);

//樹是空的嗎?
bool TreeIsEmpty(const Tree * ptoTree);

//樹滿了嗎?假定我們隊樹的最大項目樹有要求
bool TreeIsFull(const Tree * ptoTree);

//查詢樹的項目數
bool TreeSize(const Tree * ptoTree);

//向樹添加項目
bool AddMovieToTree(const Item * ptoItem,Tree * ptoTree);

//從樹刪除項目
bool DleteMovieFromTree(const Item * ptoItem,Tree * ptoTree);

//項目是否重複?
bool IsInTree(const Item * ptoItem, Tree * ptoTree);

//遍歷樹的項目
void TraverseTree(const Tree * ptoTree,void (* ptoFunc) (Item item));

完整程序如下:
binarySearchTree.h

//
// Created by bob on 2018/11/14.
//

#ifndef LEARNINGC_BINARYSEARCHTREE_H
#define LEARNINGC_BINARYSEARCHTREE_H

#include <stdbool.h>

#define MAX_ITEMS 40
#define TITLE_MAX_CHARS 40
typedef struct movie {
    char title[TITLE_MAX_CHARS];
    int year;
} Item;

typedef struct node {
    Item  movie;
    struct node * left;
    struct node * right;
} Node;

typedef struct tree {
    Node * root;
    int size;
} Tree;

typedef struct pair {
    Node * parent;
    Node * child;
} Pair;

void InitializeTree(Tree * ptoTree);

bool TreeIsEmpty(const Tree * ptoTree);

bool TreeIsFull(const Tree * ptoTree);

int TreeSize(const Tree * ptoTree);

bool AddMovieToTree(const Item * ptoItem,Tree * ptoTree);

bool DleteMovieFromTree(const Item * ptoItem,Tree * ptoTree);

bool IsInTree(const Item * ptoItem, Tree * ptoTree);

void TraverseTree(const Tree * ptoTree,void (* ptoFunc) (Item item));

void ClearTree(Tree * ptoTree);

#endif //LEARNINGC_BINARYSEARCHTREE_H

binarySearchTree.c

//
// Created by bob on 2018/11/14.
//

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "binarySearchTree.h"

static Pair SeekItem(const Item *, const Tree *);
static bool ToLeft(const Item * p1, const Item * p2);
static bool ToRight(const Item * p1, const Item * p2);
static Node * MakeNode(const Item * ptoItem);
static bool AddNodeToTree(Node * new_node, Node * root);
static bool DeleteNode(Node ** p);
static void Traverse(const Tree * ptoTree,void (*pfunc) (Item movie));
static void InOrder(const Node * parent, void (*pfunc) (Item movie));
static void DeleteAllNodes(Node * parent);
Pair SeekItem(const Item * ptoItem, const Tree * ptoTree) {

    Pair scan;
    scan.parent = NULL;
    scan.child = ptoTree->root;

    if(scan.child == NULL)
        return scan;

    while (scan.child != NULL){
        if(ToLeft(ptoItem,&(scan.child->movie))){
            scan.parent = scan.child;
            scan.child = scan.child->left;
        } else if(ToRight(ptoItem,&(scan.child->movie))){
            scan.parent = scan.child;
            scan.child = scan.child->right;
        } else{
            break;
        }
    }

    return scan;
}

bool ToLeft(const Item *p1, const Item *p2) {
    int compl;

    if((compl = strcmp(p1->title,p2->title)) < 0)
        return true;
    else if((compl = strcmp(p1->title,p2->title)) == 0 && p1->year < p2->year)
        return true;
    else
        return false;
}

bool ToRight(const Item *p1, const Item *p2) {
     int compl;

     if((compl = strcmp(p1->title,p2->title)) > 0)
         return true;
     else if((compl = strcmp(p1->title,p2->title)) == 0 && p1->year > p2->year)
         return true;
     else
         return false;
}

Node * MakeNode(const Item *ptoItem) {
    Node * new_node;
    new_node = (Node *) malloc(sizeof(Node));

    if(new_node == NULL){
        fprintf(stderr,"Can not allocate memory to create a node.\n");
        return NULL;
    }
    if(ptoItem != NULL){
        new_node->movie = * ptoItem;
        new_node->left = NULL;
        new_node->right = NULL;
    }

    return new_node;
}

bool AddNodeToTree(Node *new_node, Node * root) {
    if(ToLeft(&new_node->movie,&root->movie)){
        if(root->left == NULL)
            root->left = new_node;
        else
            AddNodeToTree(new_node,root->left);
    }else if(ToRight(&new_node->movie,&root->movie)){
        if(root->right == NULL)
            root->right = new_node;
        else
            AddNodeToTree(new_node,root->right);
    }else{
        fprintf(stderr,"Error in locating the inserting index of this node.\n");
        exit(1);
    }
    return true;
}

bool DeleteNode(Node ** p) {
    Node * p_temp;
    puts("Deleting the movie:");
    puts((*p)->movie.title);
    if((*p)->left == NULL){
        p_temp = *p;
        *p = (*p)->right;
        free(p_temp);
    } else if((*p)->right == NULL){
        p_temp = *p;
        *p = (*p)->left;
        free(p_temp);
    }else{
        for (p_temp = (*p)->left;p_temp->right != NULL;p_temp = p_temp->right)
            continue;
        p_temp->right = (*p)->right;
        p_temp = *p;
        *p = (*p)->left;
        free(p_temp);
    }
}

void Traverse(const Tree *ptoTree, void (*pfunc)(Item)) {
    if(ptoTree != NULL)
        InOrder(ptoTree->root,pfunc);
}

void InOrder(const Node *parent, void (*pfunc)(Item)) {
    if(parent != NULL){
        InOrder(parent->left,pfunc);
        (*pfunc)(parent->movie);
        InOrder(parent->right,pfunc);
    }
}

void DeleteAllNodes(Node *parent) {
    Node * ptoRight;
    if(parent != NULL){
        ptoRight = parent->right;
        DeleteAllNodes(parent->left);
        free(parent);
        DeleteAllNodes(ptoRight);
    }
}


void InitializeTree(Tree *ptoTree) {
    ptoTree -> root = NULL;
    ptoTree->size=0;
}

bool TreeIsEmpty(const Tree *ptoTree) {
    if(ptoTree->root == NULL)
        return 1;
    else
        return 0;
}

bool TreeIsFull(const Tree *ptoTree) {
    if(ptoTree->size >= MAX_ITEMS)
        return true;
    else
        return false;
}

int TreeSize(const Tree *ptoTree) {
    return ptoTree->size;
}

bool AddMovieToTree(const Item * ptoItem, Tree * ptoTree) {
    if(ptoItem == NULL | strlen(ptoItem->title) == 0 | ptoItem->year < 1800){
        fprintf(stderr,"The movie you are adding has something wrong.");
        return false;
    }
    if(TreeIsFull(ptoTree)){
        fprintf(stderr,"The tree is full. You can not add a movie to a full tree");
        return false;
    }
    if(SeekItem(ptoItem,ptoTree).child != NULL){
        fprintf(stderr,"Trying to add duplicate movie.\n");
    }

    Node * new_node;

    new_node = MakeNode(ptoItem);
//    if(new_node == NULL){
//
//    }//無需判斷new_node是否爲空指針,MakeNode函數裏已經做過了

    ptoTree->size++;

    if(ptoTree->root == NULL)
        ptoTree->root = new_node;
    else
        AddNodeToTree(new_node,ptoTree->root);

    return true;

}

bool DleteMovieFromTree(const Item *ptoItem, Tree *ptoTree) {
    Pair scan;
    scan = SeekItem(ptoItem,ptoTree);

    if(scan.child == NULL)
        return false;

    if(scan.parent == NULL)
        DeleteNode(&ptoTree->root);
    else if(scan.parent->left == scan.child)
        //這裏不能傳scan.child,雖染這兩個指向的是同一個node,但我們必須得傳父節點持有的指針的指針
        DeleteNode(&scan.parent->left);
    else
        DeleteNode(&scan.parent->right);

    ptoTree->size--;

    return true;
}

bool IsInTree(const Item *ptoItem, Tree *ptoTree) {
    return SeekItem(ptoItem,ptoTree).child != NULL;
}

void TraverseTree(const Tree *ptoTree, void (*ptoFunc)(Item)) {
    Traverse(ptoTree,ptoFunc);
}

void ClearTree(Tree *ptoTree) {

    if(ptoTree == NULL)
        return;
    else
        DeleteAllNodes(ptoTree->root);

    ptoTree->root = NULL;
    ptoTree->size = 0;
}


好亂,日後再改。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章