1. 程式人生 > >樹的實現與操作(C語言實現)

樹的實現與操作(C語言實現)

首先來簡單說下一些關於的基本概念。

樹是一種非線性的資料結構

1,樹是由 n(n>=0)個結點組成的有限集合

如果n = 0 ,稱為空樹

如果n > 0,則:

有一個特定的稱之為根(root)的結點,它只有直接後繼,但沒有直接前驅

除了根以外的其他結點劃分為:m(m>=0)個互不相交的有限集合,T0,T1,T2…Tn-1,每個集合又是一棵樹,並且稱之為根的子樹

2,樹中的概念:

樹的結點包括一個數據及若干指向子樹的分支

結點擁有的子樹樹稱為結點的度

度為0的結點稱為葉結點

度不為0的結點稱為分支結

樹的度的定義為所有結點中的度的最大值


3,樹中結點之間的關係

(1)結點的直接後繼稱為該結點的孩子

(2)相應的該結點稱為孩子的雙親

(3)結點的孩子的孩子的……稱為該結點的子孫

(4)相應的該結點稱為子孫的祖先

(5)同一個雙親的孩子之間互稱兄弟

4,樹的深度或高度

(1)結點的層次

(2)根為第1

(3)根的孩子為第2

(4)……

(5)樹中結點的最大層次稱為樹的深度或高度

5,如果樹中結點的各子樹從左向右是有次序的,樹間不能互換位置,則稱該樹為有序樹,否則為無序樹。

6,森林是由 n(n >=0)棵互不相交的樹組成的集合

7,樹的相關操作

樹的操作

樹的一些常用操作

->建立樹

->銷燬樹

->清空樹

->插入結點

->刪除結點

->

獲取結點

->獲取根結點

->獲取樹的結點數

->獲取樹的高度

    ->獲取樹的度

樹在程式中表現為一種特殊的資料型別

樹的操作在程式中的表現為一組函式

Tree:

Tree*Tree_Create();

voidTree_Destroy(Tree* tree);

voidTree_Clear(Tree* tree);

intTree_Insert(Tree* tree, TreeNode* node, int pos);

TreeNode*Tree_Delete(Tree* tree, int pos);

TreeNode*Tree_Get(Tree* tree, int pos);

TreeNode*Tree_Root(Tree* tree);

intTree_Height(Tree* tree);

intTree_Count(Tree* tree);

intTree_Degree(Tree* tree);


再來說下,這裡樹的基本儲存結構。假定我們初始有一棵樹,那麼我們如何來規定他的儲存結構呢?

   首先,我們規定每個樹結點中有三個屬性(1)表示其父親的指標(2)表示結點中的資料(3)表示孩子的連結串列,這裡為什麼是個連結串列呢?因為一個結點的的孩子可能有一個,也有可能有多個,所以用一個連結串列表示最為合適了。

   第二,每個樹之間的關係,我們可以模仿二叉樹中的先序遍歷思想,對這顆樹進行遍歷,我們知道,遍歷的結果肯定是個序列,那麼我們此時就可以果斷的把這種序列認為是一種連結串列結構,那麼後期對於樹的操作也就可以移植到連結串列上來了。

   最後,關於樹的深度、度、刪除、根結點的獲取與計算,都是在表示那顆樹的結點上來操作的。那麼這裡特別說明一下,由於整個樹存在兩個連結串列,所以對於每次刪除,插入都要向兩個連結串列中刪除和插入。(一個結點既要存在於他父親的孩子連結串列中,又要存在於表示整棵樹的連結串列中

這裡我們用到了連結串列的知識,如果對於連結串列不熟悉,可以參閱

原始碼:

#ifndef _GTREE_H_
#define _GTREE_H_

typedef void GTree;
typedef void GTreeData;
typedef void (GTree_Printf)(GTreeData*);

GTree* GTree_Create();

void GTree_Destroy(GTree* tree);

void GTree_Clear(GTree* tree);

int GTree_Insert(GTree* tree, GTreeData* data, int pPos);

GTreeData* GTree_Delete(GTree* tree, int pos);

GTreeData* GTree_Get(GTree* tree, int pos);

GTreeData* GTree_Root(GTree* tree);

int GTree_Height(GTree* tree);

int GTree_Count(GTree* tree);

int GTree_Degree(GTree* tree);

void GTree_Display(GTree* tree, GTree_Printf* pFunc, int gap, char div);

#endif


CPP實現部分:

#include "stdafx.h"
#include <malloc.h>
#include "GTree.h"
#include "LinkList.h"

//樹中的結點
typedef struct _tag_GTreeNode GTreeNode;
struct _tag_GTreeNode
{
    GTreeData* data;
    GTreeNode* parent;
    LinkList* child;
};

//樹
typedef struct _tag_TLNode TLNode;
struct _tag_TLNode
{
    LinkListNode header;
    GTreeNode* node;
};


//列印樹
static void recursive_display(GTreeNode* node, GTree_Printf* pFunc, int format, int gap, char div)
{
    int i = 0;
    
    if( (node != NULL) && (pFunc != NULL) )
    {
        for(i=0; i<format; i++)
        {
            printf("%c", div);
        }
    
        pFunc(node->data);
    
        printf("\n");
    
        for(i=0; i<LinkList_Length(node->child); i++)
        {
            TLNode* trNode = (TLNode*)LinkList_Get(node->child, i);
            
            recursive_display(trNode->node, pFunc, format + gap, gap, div);
        }
    }
}

static void recursive_delete(LinkList* list, GTreeNode* node)
{
    if( (list != NULL) && (node != NULL) )
    {
        GTreeNode* parent = node->parent;
        int index = -1;
        int i = 0;
        //將結點從表示樹的連結串列中刪除
        for(i=0; i<LinkList_Length(list); i++)
        {
            TLNode* trNode = (TLNode*)LinkList_Get(list, i);
             
            if( trNode->node == node )
            {
                LinkList_Delete(list, i);
                
                free(trNode);
                
                index = i;
                
                break;
            }
        }
          
		//如果index>0,則表明他有父親
        if( index >= 0 )
        {  
            if( parent != NULL )
            {
				//將他從他父親的孩子連結串列中刪除
                 for(i=0; i<LinkList_Length(parent->child); i++)
                 {
                     TLNode* trNode = (TLNode*)LinkList_Get(parent->child, i);
                     
                     if( trNode->node == node )
                     {
                         LinkList_Delete(parent->child, i);
                         
                         free(trNode);
                         
                         break;
                     }
                 }               
            }
            
			//如果他有兒子,將他的兒子們都殺死
            while( LinkList_Length(node->child) > 0 )
            {
                TLNode* trNode = (TLNode*)LinkList_Get(node->child, 0);
                
                recursive_delete(list, trNode->node);
            }
            
            LinkList_Destroy(node->child);
        
            free(node);
        }
    }
}

static int recursive_height(GTreeNode* node)
{
    int ret = 0;
    
    if( node != NULL )
    {
        int subHeight = 0;
        int i = 0;
        
        for(i=0; i<LinkList_Length(node->child); i++)
        {
            TLNode* trNode = (TLNode*)LinkList_Get(node->child, i);
            
            subHeight = recursive_height(trNode->node);
            
            if( ret < subHeight )
            {
                ret = subHeight;
            }
        }
        
        ret = ret + 1;
    }
    
    return ret;
}

static int recursive_degree(GTreeNode* node)
{
int ret = -1;
    
    if( node != NULL )
    {
        int subDegree = 0;
        int i = 0;
        
        ret = LinkList_Length(node->child);
        
        for(i=0; i<LinkList_Length(node->child); i++)
        {
            TLNode* trNode = (TLNode*)LinkList_Get(node->child, i);
            
            subDegree = recursive_degree(trNode->node);
            
            if( ret < subDegree )
            {
                ret = subDegree;
            }
        }
    }
    
    return ret;
}

GTree* GTree_Create()
{
    return LinkList_Create();
}

void GTree_Destroy(GTree* tree)
{
    GTree_Clear(tree);
    LinkList_Destroy(tree);
}

void GTree_Clear(GTree* tree)
{
     GTree_Delete(tree, 0);
}

int GTree_Insert(GTree* tree, GTreeData* data, int pPos)
{
    LinkList* list = (LinkList*)tree;  //傳進被插入的樹,表示的實質為連結串列
	//合法性判斷
    int ret = (list != NULL) && (data != NULL) && (pPos < LinkList_Length(list)); //所插入的結點必須在樹當中,
																				  //故而是pPos < LinkList_Length(list)
    
    if( ret )
    {
        TLNode* trNode = (TLNode*)malloc(sizeof(TLNode));    //建立一個結點,用於記錄儲存樹的連結串列中的結點
        TLNode* cldNode = (TLNode*)malloc(sizeof(TLNode)); //孩子(是個連結串列)
        TLNode* pNode = (TLNode*)LinkList_Get(list, pPos);  //從表示樹的連結串列中獲取要插入結點父母親
        GTreeNode* cNode = (GTreeNode*)malloc(sizeof(GTreeNode));  //要插入的結點,用於接收傳進來的data
        
        ret = (trNode != NULL) && (cldNode != NULL) && (cNode != NULL); //樹中結點不能為空,該結點
        
        if( ret )
        {
            cNode->data = data;     //儲存資料
            cNode->parent = NULL;   //現在還弄不清他的父母親是誰
            cNode->child = LinkList_Create();  //要插入的結點的孩子是個連結串列
            
            trNode->node = cNode;  //將要插入的結點賦值給表示樹的連結串列
            cldNode->node = cNode; //將要插入的結點賦值給樹結點中的孩子連結串列
            
            LinkList_Insert(list, (LinkListNode*)trNode, LinkList_Length(list)); //向表示樹的連結串列中插入
            
            if( pNode != NULL )  //如果要插入的結點有父節點,就向父節點的子結點連結串列插入該結點
            {
                cNode->parent = pNode->node;//認親的過程
                
				//正式加入大家庭
                LinkList_Insert(pNode->node->child, (LinkListNode*)cldNode, LinkList_Length(pNode->node->child));
            }
        }
        else
        {
            free(trNode);
            free(cldNode);
            free(cNode);
        }
    }
    
    return ret;
}

//刪除結點
GTreeData* GTree_Delete(GTree* tree, int pos)
{
    TLNode* trNode = (TLNode*)LinkList_Get(tree, pos);
    GTreeData* ret = NULL;
    
    if( trNode != NULL )
    {
        ret = trNode->node->data;
        
        recursive_delete(tree, trNode->node);
    }
    
    return ret;
}

//獲得指定位置的結點
GTreeData* GTree_Get(GTree* tree, int pos)
{
    TLNode* trNode = (TLNode*)LinkList_Get(tree, pos);
    GTreeData* ret = NULL;
    
    if( trNode != NULL )
    {
        ret = trNode->node->data;
    }
    
    return ret;
}

//獲得根結點
GTreeData* GTree_Root(GTree* tree)
{
    return GTree_Get(tree, 0);
}


//求樹的高度
int GTree_Height(GTree* tree)
{
    TLNode* trNode = (TLNode*)LinkList_Get(tree, 0);
    int ret = 0;
    
    if( trNode != NULL )
    {
        ret = recursive_height(trNode->node);
    }
    
    return ret;
}

//求樹的結點個數
int GTree_Count(GTree* tree)
{
    return LinkList_Length(tree);
}

//求樹的度
int GTree_Degree(GTree* tree)
{
    TLNode* trNode = (TLNode*)LinkList_Get(tree, 0);
    int ret = -1;
    
    if( trNode != NULL )
    {
        ret = recursive_degree(trNode->node);
    }
    
    return ret;
}

void GTree_Display(GTree* tree, GTree_Printf* pFunc, int gap, char div)
{
    TLNode* trNode = (TLNode*)LinkList_Get(tree, 0);
    
    if( (trNode != NULL) && (pFunc != NULL) )
    {  
        recursive_display(trNode->node, pFunc, 0, gap, div);
    }
}

主函式操作部分:
// 樹.cpp : 定義控制檯應用程式的入口點。
//

#include "stdafx.h"
#include "GTree.h"
#include <stdlib.h>

void printf_data(GTreeData* data)
{
    printf("%c", (int)data);
}
int _tmain(int argc, _TCHAR* argv[])
{

	GTree* tree = GTree_Create();
    int i = 0;
    
    GTree_Insert(tree, (GTreeData*)'A', -1);
    GTree_Insert(tree, (GTreeData*)'B', 0);
    GTree_Insert(tree, (GTreeData*)'C', 0);
    GTree_Insert(tree, (GTreeData*)'D', 0);
    GTree_Insert(tree, (GTreeData*)'E', 1);
    GTree_Insert(tree, (GTreeData*)'F', 1);
    GTree_Insert(tree, (GTreeData*)'H', 3);
    GTree_Insert(tree, (GTreeData*)'I', 3);
    GTree_Insert(tree, (GTreeData*)'J', 3);
    
    printf("Tree Height: %d\n", GTree_Height(tree));
    printf("Tree Degree: %d\n", GTree_Degree(tree));
    printf("Full Tree:\n");
    
    GTree_Display(tree, printf_data, 2, ' ');
    
    printf("Get Tree Data:\n");
    
    for(i=0; i<GTree_Count(tree); i++)
    {
        printf_data(GTree_Get(tree, i));
        printf("\n");
    }
    
    printf("Get Root Data:\n");
    
    printf_data(GTree_Root(tree));
    
    printf("\n");
    
    GTree_Delete(tree, 3);
     
    printf("After Deleting D:\n");
    
    GTree_Display(tree, printf_data, 2, '-');
    
    GTree_Clear(tree);
    
    printf("After Clearing Tree:\n");
    
    GTree_Display(tree, printf_data, 2, '.');
        
    GTree_Destroy(tree);

	system("pause");
	return 0;
}

執行結果:
Tree Height: 3
Tree Degree: 3
Full Tree:
A
  B
    E
    F
  C
  D
    H
    I
    J
Get Tree Data:
A
B
C
D
E
F
H
I
J
Get Root Data:
A
After Deleting D:
A
--B
----E
----F
--C
After Clearing Tree:
請按任意鍵繼續. . .


如有錯誤,望不吝指出。