二叉树,约瑟夫,多项式合并!

2015.2.9
星期一 晴

树的基本概念:

度数:一个节点的子树的个数为该节点的度数,一颗数的度数是指该树中节点的最大度数
树叶或者终端节点:度数为0的节点
高度或者深度:节点的层数等于父节点的层数加1,根节点的层数定义为1,树中节点层数最大值称为该树的高度或者深度
有序树:若树中每个节点的各子树的排列为从左到右,不能交换,即兄弟之间是有序的,则称该树为有序树
满二叉树:深度为K时有2^k-1个节点的二叉树
完全二叉树:只有最下面两层就度数小于2的节点,且最下面一层的叶节点集中在最左边的若干位置上。

对于完全二叉树有以下特点: 设节点数为n,某节点编号为i

数组实现:如果有N个节点需要N+1个数组空间,把数组0的位置空出来,从1开始排列,利用下面的公式计算每个i节点子节点的下标:
左子节点:2*i,右子节点:2*i+1;

满足:2*i<=n时,i子节点存在左孩子,且编号为2*i
满足:2*i+1<=n时,i子节点存在左孩子,且编号为2*i

用链表和递归函数实现一个树的创建:中间有很多打印的程序,方便看过程。
#include <stdio.h>
#include <stdlib.h>

typedef char bt_data_t;

typedef struct tree_node_t{
bt_data_t data;
struct tree_node_t *lchild,*rchild;
}bitree_t;

bitree_t *Create_Bitree(int i, bt_data_t a[],int n);

static int indent = 0;
static int step = 0;

int main()
{
bt_data_t bt_array[] = {0,'a','b','c','d','e','f','g','h','i','j'};
bt_data_t bt_array[] = {0,'a','b','c',0,0,0,0,'h','i','j'}; //将数组改成非完全二叉树,补0

bitree_t *root;
printf("Begin creating B-tree ... ");

root = Create_Bitree(1,bt_array,sizeof(bt_array)/sizeof(bt_data_t) - 1); //从根节点开始,调用递归函数创建二叉树的所有节点并插入数据
printf("Finished! ");

return 0;
}

bitree_t *Create_Bitree(int i,bt_data_t a [],int n) //递归函数的创建
{
bitree_t *root;
int j;

printf("-------------->step<%2d> ",step++);

indent++;

root = (bitree_t *)malloc(sizeof(bitree_t));
root->data = a[i]; //将数据写入结构体
printf("%d*cRoot(%c) ",indent,'-',root->data);

j = 2*i;
if(j <= n) //对于非完全而二叉树这样修改:if(j <= n && a[j] != '0') //判断是否存在左子树
{
printf("%*cRoot(%d)->Left(%d) ",indent,'-',i,j);
root->lchild = Create_Bitree(j, a, n);
}
else
{
printf("%*cRoot(%d)->Left(NULL) ",indent,'-',i);
root->lchild = NULL; //不存在左子树,怎返回NULL
}

j = 2*i+1;
if(j <= n) //对于非完全而二叉树这样修改:if(j <= n && a[j] != '0') //判断是否存在右子树
{
printf("%*cRoot(%d)->Right(%d) ",indent,'-',i,j);
root->rchild = Create_Bitree(j, a, n);
}
else
{
printf("%*cRoot(%d)->Right(NULL) ",indent,'-',i);
root->rchild = NULL;
}

indent--;

printf("<--------------step<%2d> ",step++);

return root;
}

执行效果:

lg@lg-desktop:/mnt/hgfs/source test/pdf$ gcc bt_create1.c
lg@lg-desktop:/mnt/hgfs/source test/pdf$ ./a.out
Begin creating B-tree ...
-------------->step< 0>
1*cRoot(-)
-Root(1)->Left(2)
-------------->step< 1>
2*cRoot(-)
-Root(2)->Left(4)
-------------->step< 2>
3*cRoot(-)
-Root(4)->Left(8)
-------------->step< 3>
4*cRoot(-)
-Root(8)->Left(NULL)
-Root(8)->Right(NULL)
<--------------step< 4>
-Root(4)->Right(9)
-------------->step< 5>
4*cRoot(-)
-Root(9)->Left(NULL)
-Root(9)->Right(NULL)
<--------------step< 6>
<--------------step< 7>
-Root(2)->Right(5)
-------------->step< 8>
3*cRoot(-)
-Root(5)->Left(10)
-------------->step< 9>
4*cRoot(-)
-Root(10)->Left(NULL)
-Root(10)->Right(NULL)
<--------------step<10>
-Root(5)->Right(NULL)
<--------------step<11>
<--------------step<12>
-Root(1)->Right(3)
-------------->step<13>
2*cRoot(-)
-Root(3)->Left(6)
-------------->step<14>
3*cRoot(-)
-Root(6)->Left(NULL)
-Root(6)->Right(NULL)
<--------------step<15>
-Root(3)->Right(7)
-------------->step<16>
3*cRoot(-)
-Root(7)->Left(NULL)
-Root(7)->Right(NULL)
<--------------step<17>
<--------------step<18>
<--------------step<19>
Finished!


用函数指针可以给已经写好的函数增加额外的功能!!!!!!!!!!!

将数组data_t array[] = {0,'A','B','C','D','E','0','F','0','0','G','H','0','0','I'};中的字符插入数的相应位置,
并按照不同的遍历顺序打印出来:依次先序,中序,后序;

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

typedef int data_t;

typedef struct tree{
data_t data;
struct tree *lchild;
struct tree *rchild;
}bitree_t;

bitree_t *Create_Bitree(int i,data_t a[],int n);
void Pre_Order(bitree_t *bt);
void In_Order(bitree_t *bt);
void Post_Order(bitree_t *bt);

main()
{
data_t array[] = {0,'A','B','C','D','E','0','F','0','0','G','H','0','0','I'};
bitree_t *root;
int len;

len = sizeof(array)/sizeof(data_t) - 1;
printf("begain create b-tree.... ");

root = Create_Bitree(1,array,len);

printf("finish ");

printf("Pre_Order = ");
Pre_Order(root);
putchar(' ');
printf("In_Order = ");
In_Order(root);
putchar(' ');
printf("Post_Order = ");
Post_Order(root);
putchar(' ');


}

bitree_t *Create_Bitree(int i,data_t a[],int n) //建立树的程序和上面的程序一样
{
bitree_t *root;
int j;

root = (bitree_t *)malloc(sizeof(bitree_t));
if(root == NULL)
{
return NULL;
}

root->data = a[i];

j = 2 * i;
if((j <= n) && a[j] != '0')
{
root->lchild = Create_Bitree(j,a,n); //递归创建
}
else
{
root->lchild = NULL;
}

j = 2 * i + 1;
if((j <= n) && a[j] != '0')
{
root->rchild = Create_Bitree(j,a,n); //递归创建
}
else
{
root->rchild = NULL;
}

return root;
}

void Pre_Order(bitree_t *bt) //先序遍历二叉树,并打印出找到的数据
{
if(bt == NULL)
{
return ;
}
printf("%3c",bt->data); //根节点
Pre_Order(bt->lchild); //左子树
Pre_Order(bt->rchild); //右子树

//return ;
}

void In_Order(bitree_t *bt) //中序遍历二叉树,并打印出找到的数据
{
if(bt == NULL)
{
return ;
}
In_Order(bt->lchild); //左子树
printf("%3c",bt->data);//根节点
In_Order(bt->rchild); //右子树
}

void Post_Order(bitree_t *bt) //先序遍历二叉树,并打印出找到的数据
{
if(bt == NULL)
{
return ;
}
Post_Order(bt->lchild); //左子树
Post_Order(bt->rchild); //右子树
printf("%3c",bt->data); //根节点

}


执行效果:

lg@lg-desktop:/mnt/hgfs/source test/pdf$ gcc testtree.c
lg@lg-desktop:/mnt/hgfs/source test/pdf$ ./a.out
begain create b-tree....
finish
Pre_Order = A B D E G H C F I
In_Order = D B G E H A C I F
Post_Order = D G H E B I F C A
lg@lg-desktop:/mnt/hgfs/source test/pdf$


约瑟夫问题的链表的实现:
#include <stdio.h>
#include <stdlib.h>

void joseph(int n, int k, int m) //总共n个人,从第k个人的下一个开始作为1,数到m的人出局
{
int i;
linklist_t p,L,r;
L = NULL;

for(i = 1; i <= n; i++) //建立循环链表
{
p = (linklist_t)malloc(sizeof(linknode_t));
p->data = i;
if(L == NULL)
{
L = p;
}
else
{
r->next = p;
}
r = p;
}

for(i = 1; i < k; i++) //找到第一个开始计数的位置
{
r = r->next;
}
while(r->next != r) //人数大于1
{
for(i = 1; i <= m-2; i++) //这里是一个技巧性很强的操作,巧妙地利用已有的指针释放出局的数据,避免了利用额外的指针来做标记动作
{
r = r->next;
}
p = r->next;
r->next = p->next;
printf("%d",p->data);
free(p);
r = r->next;
}
printf("%d ",r->data);

}

多项式的表示和相加:这里的操作很很特别,用两个结构体组成一个完整的多项式的表示,包括多项式的系数,指数,和指向下一个节点的指针

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

typedef struct{ //这个结构体中包括了多项式的系数,指数
float coaf;
int exp;
}data_t;

typedef struct node{ //第二个结构体包括了第一个结构体和一个指向下个节点的指针
data_t data;
struct node *next;
}linknode_t;*linklist_t;

void Addpoly(linklist_t pa,linklist_t pb) //这个函数时多项式的所有项进项操作,包括从小到大的排序和合并的过程,一次性全部完成。
{
linklist_t pre,u;
float sum;

pre = pa;
pa = pa->next;

u = pb;
pb = pb->next;

free(u);

while(pa && pb)
{
if(pa->data.exp < pb->data.exp) //将小的多项式放在结构体的前面
{
pre->next = pa;
pre = pa;
pa = pa->next;
}

if(pa->data.exp > pb->data.exp)
{
pre->next = pb;
pre = pb;
pb = pb->next;
}
else
{
sum = pa->data.coaf + pb->data.coaf; //合并多项式的系数
if(sum != 0.0)
{
pa->data.coaf = sum;
pre->next = pa;
pre = pa;
pa = pa->next;
}
else
{
u = pa; //当节点合并后的系数为0后,删除相应的节点pa
pa = pa->next;
free(u);
}

u = pb; //删除相应的节点pa
pb = pb->next;
free(u);
}

}
if(pa != NULL) //当其中一个节点遍历完毕后,将还有数据的链表直接放到合并后的链表的后面
{
pre->next = pa;
}
else
{
pre->next = pb;
}
}

***************************************************************************************************************************************************************
***************************************************************************************************************************************************************
***************************************************************************************************************************************************************
***************************************************************************************************************************************************************

原文地址:https://www.cnblogs.com/cnlg/p/4282656.html