1. 程式人生 > >資料結構之通用樹(使用連結串列實現樹的儲存結構,雙親孩子表示法)

資料結構之通用樹(使用連結串列實現樹的儲存結構,雙親孩子表示法)

樹是一種非線性的資料結構,可以使用連結串列組織樹的各個節點,描述樹的一些常用操作。雙親孩子表示法是指每個結點都有一個指向其雙親的指標,每個結點都有若干個指向其孩子的指標。

標頭檔案:

tree.h

#ifndef __TREE_H__
#define __TREE_H__

#include "error.h"

struct _treeNode; //事先宣告

//孩子節點連結串列的型別
typedef struct _childNode
{
	struct _treeNode *childNode;  //指向樹節點
	struct _childNode *next;   //指向孩子節點連結串列的下一個元素
}ChildNode;

//樹節點連結串列
typedef char TreeData;
typedef struct _treeNode
{
	TreeData data;              //資料域
	struct _treeNode *parent;    //指向父節點的指標
	struct _treeNode *next;      //指向樹節點連結串列下一個節點
	struct _childNode *childlist;   //指向孩子節點連結串列頭節點
	int degree;                //頭節點
}TreeNode;

//樹型別
typedef struct _tree
{
	TreeNode *head;    //指向樹節點連結串列頭節點的指標
	int len;   //樹節點的個數
}Tree;

typedef void (*TreePrint)(TreeNode *node);

//建立一棵樹
Tree *Create_tree ();

// pos 代表要插入結點父親結點的位置
// 約定:
// 1 新插入的結點插入在當前父親結點所有孩子的右邊
// 2 根節點的位置是 0
int Insert_Tree(Tree *tree, TreeData data, int pos);

//列印樹
void Display(Tree *tree, TreePrint pFunc);

//刪除節點
int Delete(Tree *tree, int pos, TreeData *x);

//求指定位置樹節點的值
int Tree_Get(Tree* tree, int pos, TreeData *x);

// 清空樹中所有的節點
int Tree_Clear(Tree* tree);

// 樹的銷燬 
void Tree_Destroy(Tree* tree);

//獲取樹根節點的地址
TreeNode* Tree_Root(Tree* tree);

//求樹節點個數
int Tree_Count(Tree* tree);

//求樹的高度
int Tree_Height(Tree* tree);

//求樹的度
int Tree_Degree(Tree* tree);

#endif   //__TREE_H__ 

原始檔:

tree.c

#include <stdlib.h>
#include <stdio.h>
#include "tree.h"

//建立一棵樹
Tree *Create_tree ()
{
	//建立樹
	Tree *tree = (Tree *)malloc(sizeof(Tree)/sizeof(char));
	if(tree == NULL)
	{
		errno = MALLOC_ERROR;
		return NULL;
	}
	//空樹節點為0
	tree->len = 0;
	//建立樹節點連結串列頭節點
	tree->head = (TreeNode *)malloc(sizeof(TreeNode)/sizeof(char));
	if (tree->head == NULL)
	{
		free(tree);
		errno = MALLOC_ERROR;
		return NULL;
	}
	//樹中沒有節點
	tree->head->parent = NULL;
	tree->head->next   = NULL;
	tree->head->childlist    = NULL;
	
	return tree;
}

// pos 代表要插入結點父親結點的位置
// 約定:
// 1 新插入的結點插入在當前父親結點所有孩子的右邊
// 2 根節點的位置是 0
int Insert_Tree(Tree *tree, TreeData data, int pos)
{
	if (tree == NULL || pos < 0 || pos > tree->len)
	{
		errno = ERROR;
		return FALSE;
	}
	if (pos != 0 && pos == tree->len)
	{
		errno = ERROR;
		return FALSE;
	}
	
	//新建樹節點
	TreeNode *node = (TreeNode*)malloc(sizeof(TreeNode)/sizeof(char));
	if (node == NULL)
	{
		errno = MALLOC_ERROR;
		return FALSE;
	}
	node->data = data;
	node->next = NULL;
	
	//建立該新節點的孩子節點連結串列的頭節點
	node->childlist = (ChildNode*)malloc(sizeof(ChildNode)/sizeof(char));
	if (node->childlist == NULL)
	{
		errno = MALLOC_ERROR;
		free (node);
		return FALSE;
	}
	node->childlist->next = NULL;
	node->childlist->childNode = NULL;
	
	node->degree = 0;
	
	//找父節點
	int i;
	TreeNode *parent = tree->head->next;    //當前樹節點的第一個節點
	for (i = 0;i < pos;i++)
	{
		parent = parent->next;
	}
	node->parent = parent;
	
	//在父親節點的子節點連結串列中加入一個節點
	if (parent != NULL)
	{
		//建立一個孩子節點
		ChildNode *childnode = (ChildNode*)malloc(sizeof(ChildNode)/sizeof(char));
		if (childnode == NULL)
		{
			errno = MALLOC_ERROR;
			free(node->childlist);
			free(node);
			return FALSE;
		}
		childnode->next = NULL;
		childnode->childNode = node;
		//加入到父親節點子節點連結串列中
		ChildNode *tmp = parent->childlist;  //子節點連結串列的頭節點
		while (tmp->next)
		{
			tmp = tmp->next;
		}
		tmp->next = childnode;
		parent->degree += 1;
	}
	TreeNode *tmp = tree->head;
	while (tmp->next)
	{
		tmp = tmp->next;
	}
	tmp->next = node;
	tree->len += 1;
	return TRUE;
}

//遞迴列印
void r_display (TreeNode *node,TreePrint pFunc,int gap)
{
	if (node == NULL)
	{
		return;
	}
	//列印距離第一個節點的距離
	int i;
	for (i = 0; i < gap;i++)
	{
		printf ("-");
	}
	pFunc(node);  //列印節點自己
	ChildNode * child = node->childlist->next;  //該節點的第一個孩子
	//列印該節點的孩子
	while(child)
	{
		r_display (child->childNode,pFunc,gap+4);
		child = child->next;
	}
}

//列印樹
void Display(Tree *tree, TreePrint pFunc)
{
	if (tree == NULL)
	{
		errno = ERROR;
		return;
	}
	r_display (tree->head->next,pFunc,0);
}

//遞迴刪除
void r_delete(Tree *tree,TreeNode *node)
{
	if (tree == NULL || node == NULL)
	{
		return;
	}
	//從樹節點連結串列中移除這個節點,找node的前一個節點
	TreeNode *tmp = tree->head;  //連結串列的頭節點
	while (tmp->next)
	{
		if (tmp->next == node)
		{
			tmp->next = node->next;
			tree->len --;
			break;
		}
		tmp = tmp->next;
	}
	
	//將父親節點中子節點連結串列中指向node的節點刪除
	TreeNode *parent = node->parent;
	if (parent != NULL)
	{
		ChildNode *tmp = parent->childlist;  //子節點連結串列的頭節點
		while (tmp->next)
		{
			if (tmp->next->childNode == node)
			{
				ChildNode *p = tmp->next;
				tmp->next = p->next;
				free(p);
				parent->degree --;
				break;
			}
			tmp = tmp->next;
		}
	}
	
	//將該節點的孩子節點刪掉
	ChildNode* child = node->childlist->next;//子節點連結串列中第一個節點
	while (child)
	{
		ChildNode * pchild = child->next;
		r_delete (tree,child->childNode);
		child = pchild;
	}
	free(node->childlist);
	free(node);
}

//刪除節點
int Delete(Tree *tree, int pos, TreeData *x)
{
	if (tree == NULL || pos < 0 || pos >= tree->len || x == NULL)
	{
		errno = ERROR;
		return FALSE;
	}
	int i;
	TreeNode *current = tree->head->next;
	for (i = 0;i < pos;i++)
	{
		current = current->next;
	}
	*x = current->data;
	
	r_delete (tree,current);
	return TRUE;
}


//求指定位置樹節點的值
int Tree_Get(Tree* tree, int pos, TreeData *x)
{
	if (tree == NULL || pos < 0 || pos >= tree->len)
	{
		errno = ERROR;
		return FALSE;
	}
	
	int i;
	// 找結點
	TreeNode* current = tree->head->next;  
	for (i = 0; i < pos; i++)
	{
		current = current->next;
	}
	
	*x = current->data;
	
	return TRUE;
}

// 清空樹中所有的節點
int Tree_Clear(Tree* tree)
{
	if (tree == NULL)
	{
		errno = ERROR;
		return FALSE;
	}
	
	TreeData x;
	return Delete (tree, 0, &x);
}

//樹的銷燬
void Tree_Destroy(Tree* tree)
{
	if (tree == NULL)
	{
		errno = ERROR;
		return;
	}
	
	Tree_Clear(tree);
	
	free (tree->head);
	free (tree);
}

//獲取樹根節點的地址
TreeNode* Tree_Root(Tree* tree)
{
	if (tree == NULL)
	{
		errno = ERROR;
		return NULL;
	}
	
	return tree->head->next;
}

//求樹節點個數
int Tree_Count(Tree* tree)
{
	if (tree == NULL)
	{
		errno = ERROR;
		return FALSE;
	}
	
	return tree->len;
}

//遞迴求高度
int r_height (TreeNode* node)
{
	if (node == NULL)
	{
		errno = ERROR;
		return FALSE;
	}
	int Height = 0;
	int max = 0;
	ChildNode* child = node->childlist->next;
	while (child)
	{
		Height = r_height (child->childNode);
		if (Height > max)
		{
			max = Height;
		}
		child = child->next;
	}
	return max + 1;
}

//求樹的高度
int Tree_Height(Tree* tree)
{
	if (tree == NULL)
	{
		errno = ERROR;
		return FALSE;
	}
	
	int height = r_height(tree->head->next);
	return height;
}

//遞迴求度
int r_degree (TreeNode* node)
{
	if (node == NULL)
	{
		errno = ERROR;
		return FALSE;
	}
	int Degree = 0;
	int max = node->degree;
	ChildNode* child = node->childlist->next;
	while (child)
	{
		Degree = r_degree (child->childNode);
		if (Degree > max)
		{
			max = Degree;
		}
		child = child->next;
	}
	return max;
}

//求樹的度
int Tree_Degree(Tree* tree)
{
	if (tree == NULL)
	{
		errno = ERROR;
		return FALSE;
	}
	
	int degree = r_degree(tree->head->next);
	return degree;
}


關於用連結串列實現樹的儲存結構(雙親孩子表示法)以及更多的操作,可以大家一起去實現。