数据结构

双亲表示法:
就是定义一个数组给出它的数据和双亲的下标。
可用来找节点双亲。

#include<stdio.h>
#define max 10000
typedef struct
{
    int data;
    int parent;
}PTNode;
typedef struct pTree
{
    PTNode a[max];
    int count;
}PTree;
void creat(PTree *t,int n);
int main()
{
    PTree t;
    int n;
    scanf("%d",&n);
    creat(&t,n);
}
void creat(PTree *t,int n)
{
    int i;
    printf("请输入数据和其双亲的位置\n");
    for(i=0;i<n;i++)
    {
        scanf("%d%d",&t->a[i].data,&t->a[i].parent);
    }
}

还可以多加一个firstchild就方便找当前节点的孩子,其他孩子可以用第一孩子下标得到之后的孩子下标。就是需要判断双亲下标是不是自己。因为是用层序输入的数据。
孩子表示法
方案一:
定义一个数组将树按照层序的顺序存储进入数组,然后将每一个节点的孩子所在的下标给出连接即可。

#include<stdio.h>
#define max 10000
#define degree 3
typedef struct pTNode
{
    int data;
    struct pTNode *child[degree];//根据树的最大度来定义
}PTNode;
typedef struct pTree
{
    PTNode a[max];
}PTree;
void creat(PTree *t,int n);
int main()
{
    PTree t;
    int n;
    scanf("%d",&n);
    creat(&t,n);
}
void creat(PTree *t,int n)
{
    int i,j;
    printf("请输入数据\n");
    for(i=0;i<n;i++)
    {
        scanf("%d",&t->a[i].data);
    }
    printf("请输入每个节点的孩子下标:\n格式: 第一个孩子下标 第二个孩子下标...(没有孩子输入0)\n");
    for(i=0;i<n;i++)
    {

        for(int k=0;k<degree;k++)
        {
            scanf("%d",&j);
            if(j)
            t->a[i].child[k]=&t->a[j];
            else 
            t->a[i].child[k]=0;
        }
    }
}

方案二:
定义一个数组将树按照层序的顺序存储进入数组,给出度的个数(孩子数),然后通过下标得到指针,并创建指针存放空间,将他们连接起来。需要多建立一个firstchild和child指针,firstchild是孩子链表的头。
孩子兄弟表示法
定义一个数组将树按照层序的顺序存储进入数组,然后给出每一个节点的左孩子,以及它所有的右孩子。(树转二叉树的方法)
连接规则:
1、右孩子是连接到此节点左孩子的rightsib指针的,每一个右孩子rightsib连接下一个此节点的右孩子。形成一个右孩子链表。
2、左孩子是连接到此节点的firstchild指针的

#include<stdio.h>
#define max 10000
#define degree 3
typedef struct pTNode
{
    int data;
    struct pTNode *firstchild,*rightsib;//根据树的最大度来定义
}PTNode;
typedef struct pTree
{
    PTNode a[max];
}PTree;
void creat(PTree *t,int n);
int main()
{
    PTree t;
    int n;
    scanf("%d",&n);
    creat(&t,n);
}
void creat(PTree *t,int n)
{
    int i,j,k;
    PTNode *p;
    printf("请输入数据\n");
    for(i=0;i<n;i++)
    {
        scanf("%d",&t->a[i].data);
        t->a[i].firstchild=t->a[i].rightsib=0;
    }
    for(i=0;i<n;i++)
    {
        printf("请输入节点的左孩子下标:(没有输出0)\n");
        scanf("%d",&j);
        if(j==0)
            break;
        p=t->a[i].firstchild=t->a+j;
        printf("请输入此节点的右孩子数:\n");
        scanf("%d",&k);
        for(int x=0;x<k;x++)
        {
            printf("请输入节点的右孩子下标:\n");
            scanf("%d",&j);
            p->rightsib=&t->a[j];
            p=p->rightsib;
        }
    }
}

二叉树

分为
斜数:只有右子树或者左子树。
满二叉树:
每个分子有左子树和右子树,叶节点在同一层。
完全二叉树:
就是按照层序编号树节点,不会出现编号不连续。
完全二叉树不一定是满二叉树,满二叉树一定是完全二叉树。

二叉树性质
1、第I层最多有2的i-1次方个节点。
2、深度为K的二叉树最多有2的k-1次方个节点。
3、n0为叶节点数,n1为度为1的节点数,n2为度为2的节点数,n0=n2+1.
4、n个节点的完全二叉树深度为(log2 n)+1
5、对于节点i
i/2为双亲节点
i2为该节点的左孩子
i
2+1为该节点的右孩子

二叉树的存储结构
顺序存储:用数组存储,按照层序顺序赋值,按照完全二叉树的规格来处理,没有值的赋值为0.
链式存储:
定义左孩子指针和右孩子指针,没有的为0.
可以通过前序,中序,后序的遍历方法建立二叉链表。

二叉树的遍历
前序遍历方法:根->左子树->右子树
中序遍历方法:左子树->根->右子树
后序遍历方法:左子树->右子树->根

已知前序遍历序列和中序遍历序列可以得到二叉树。
已知中序遍历序列和后序遍历序列可以得到二叉树。
如果遍历有疑惑可以通过知道遍历是递归调用函数,来确定下一个值。

typedef struct tree
{
	int data;
	struct tree *lchild,*rchild;
}Tree;
void travel(Tree *t)
{
	if(t==NULL)
	return; 
	else
	{
	printf("%d\n",t->data);//前序
	travel(t->lchild);
	travel(t->rchild);
	/*
	travel(t->lchild);
	printf("%d\n",t->data);//中序
	travel(t->rchild);
	*/
	/*
	travel(t->lchild);//后序
	travel(t->rchild);
	printf("%d\n",t->data);
	}
}

二叉树的存储
输入数据是以完全二叉树为标准没有值的地方输入#,需要按照前序、中序、后序其中一个的顺序输入数据。

typedef struct tree
{
	char data;
	struct tree *lchild,*rchild;
}Tree;
void creat(Tree **t)//t二级指针,接的是一个指针的指针。
{
	cahr c;
	scanf("%c",&c);
	if(ch=='#')
	*t=NULL; 
	else
	{
	*t=(Tree *)malloc(sizeof(Tree));//前序
	(*t)->data=ch;
	travel(t->lchild);
	travel(t->rchild);

线索二叉树
就是将二叉树不用的lchild和rchild用来存储前继和后继,最后形成一个双向链表。
多定义了
flag1(判断是前继1还是左孩子0)
flag2(判断是后继1还是右孩子0)

#include<stdio.h>
typedef struct Tree
{
    char data;
    struct Tree *lchild,*rchlid;
    int flag1,flag2;
}Tree;
Tree *pre;//前一个节点
void creat(Tree **t);
void intravel(Tree *t);
Tree *inhead(Tree *t);
void travel(Tree *t);
int main()
{
    Tree *t;
    creat(&t);//创建树
    intravel(t);//创建线索树
    travel(t);
}
void creat(Tree **t)//中序创建二叉树
{
    char c;
    scanf("%c",&c);
    if(c=='#')
        *t=NULL;
    else
    {
        creat(*t->lchild);
        *t=(Tree *)malloc(sizeof(Tree));
        (*t)->data=c;
        (*t)->flag1=(*t)->flag2=0;//默认为孩子
        creat(*t->rchild);
    }
}
void intravel(Tree *t)
{
    if(t)
    {
        creat(t->lchild);
        if(t->lchild==NULL)
        {
            t->lchild=pre;
            t->flag1=1;
        }
        if(pre->rchild==NULL)//因为当前节点无法知道后继节点,所以求的是前一个的。
        {
            pre->rchild=t;
            pre->flag2=1;
        }
        pre=t;
    }
}
Tree *inhead(Tree *t)//插入头节点
{
    Tree *head;
    static flag=1;
    if(flag)
    {
        head=(Tree *)malloc(sizeof(Tree));
        head->lchild=t;
        head->flag1=0;
        flag=0;
    }
    inhead(t->lchild);
    if(t->lchild==NULL)//找到中序第一个节点
    {
        t->lchild=head;
        t->flag1=1;
    }
    if(t->rchild==NULL)//最后一个节点,因为已经是一个双向链表了。
    {
        t->rchild=head;
        head->rchild=t;
        t->flag2=1;
        head->flag2=1;
        return head;
    }
    inhead(t->rchild);
}
void travel(Tree *t)
{
    Tree *p=t->lchild;
    while(p)
    {
        while(p->flag1==0&&p->lchild1!=t)//第一个节点是指向头节点的
        {
            p=p->lchild;
        }
        printf("%c ",p->data);
        while(p->flag2==1&&p->rchlid!=t)//中序最后一个节点是指向头节点的
        {
            p=p->rchild;
            printf("%c ",p->data);
        }
        p=p->rchlid;
    }
}

树、森林与二叉树的转换
树转二叉树
方法:
1、在所有同一个双亲兄弟之间连线
2、删除所有孩子与双亲的连线除了第一个孩子。
3、第一个孩子作为左孩子,其他作为节点右孩子。

二叉树转树
方法:
1、所有的右孩子与它双亲的双亲连线。
2、删除右节点与它双亲的连线。

森林转二叉树
方法:
1、像树一样将每一个树转成二叉树
2、后一个二叉树作为前一个二叉树根的右节点连接。

二叉树转森林
方法:
1、从根节点开始查看是否有右节点,有就分离,然后查看分离的二叉树是否有右节点,然后分离,直到没有右节点。

树与森林的遍历方法
前序:根->左子树->右子树
后序:左子树->右子树->根
森林需要一棵树,一棵树的遍历。

赫夫曼树
创建:
1、把每一个节点当作一个只有一个节点的二叉树
2、找到两个权值最小的二叉树,连接到新的节点,新的节点权值是两节点权值的和。
3、最后一个节点是根节点,n个节点创建的树有2*n-1个节点。

#include<stdio.h>
#include<stdlib.h>
typedef struct tree
{
    int data;
    int parent,lchild,rchild;
}Tree;
Tree *creat(int a[],int n);
void find(Tree *p,int *x1,int *x2,int n);
int main()
{
    int n,i;
    Tree *t;
    printf("请输入节点个数\n");
    scanf("%d",&n);
    int a[n];
    printf("请输入节点值\n");
    for(i=0;i<n;i++)
    scanf("%d",a+i);
    t=creat(a,n);
}
Tree *creat(int a[],int n)
{
    Tree *p;
    int i,x1,x2;
    p=(Tree *)malloc((n*2)*sizeof(Tree));
    for(i=1;i<=n;i++)//初始化节点
    {
        p[i].data=a[i];
        p[i].parent=p[i].lchild=p[i].rchild=0;
    }
    for(i=n+1;i<=n*2-1;i++)//初始化剩下的节点
    {
        p[i].data=0;
        p[i].parent=p[i].lchild=p[i].rchild=0;
    }
    for(i=n+1;i<=n*2-1;i++)
    {
        find(p,&x1,&x2,n);//寻找两个最小权值下标
        p[i].data=p[x1].data+p[x2].data;
        p[x1].parent=p[x2].parent=i;
    }
    return p+(n*2)-1;//最后一个就是二叉树的头节点
}
void find(Tree *p,int *x1,int *x2,int n)
{
    int flag=1,i;
    for(i=1;i<=n;i++)
    {
        if(p[i].parent!=0)
        {
            *x1=i;
            break;
        }
    }
    for(i=1;i<=n;i++)
    {
        if(p[i].parent==0)
        if(p[i].data<p[*x1].data)
        {
            *x1=i;
        }
        else
        {
            if(flag)
                {
                    *x2=i;
                    flag=0;
                }
            else if(p[i].data<p[*x2].data)
            *x2=i;
        }
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值