您的位置:首页 > 编程语言 > C语言/C++

关于AVL平衡二叉树的c语言实现(函数内部改变指针本身)

2017-05-10 15:14 411 查看
最近在看数据结构就用c语言写了一个AVL树出来,结果可以运行但无结果输出,搜索许多资料后发现是指针传递的问题,这里总结一下。

头文件(修改后的代码

#ifndef __ggh
#define __ggh
typedef int ElementType;
typedef struct AVLTreeNode *AVLTree,*Position;
struct AVLTreeNode{
ElementType Date;
AVLTree left;
AVLTree right;
int Height;
};
static int Height(Position P);
AVLTree Insert(ElementType *x,AVLTree *T);
int Max(int a,int b);
#endif
源文件

#include "stdafx.h"
#include "gg.h"
#include "stdlib.h"
#include "stdio.h"

void PreOrder(AVLTree T);
static AVLTree SingleRotateLeft(AVLTree T)
{
AVLTree T1=T->left;
T->left=T1->right;
T1->right=T;
T->Height=Max(Height(T->left),
Height(T->right))+1;
T1->Height=Max(Height(T1->left),
Height(T1->right))+1;
return T1;
}
static AVLTree SingleRotateRight(AVLTree T)
{
AVLTree T1=T->right;
T->right=T1->left;
T1->left=T;
T->Height=Max(Height(T->left),
Height(T->right))+1;
T1->Height=Max(Height(T1->left),
Height(T1->right))+1;
return T1;
}
static AVLTree DoubleRotataeleft(AVLTree T)
{
T->left=SingleRotateRight(T->left);
return SingleRotateLeft(T);
}
static AVLTree DoubleRotataeright(AVLTree T)
{
T->right=SingleRotateLeft(T->left);
return SingleRotateRight(T);
}
int Height(Position P)
{
if(P==NULL)
return -1;
else
return (P->Height);
}
AVLTree Insert(ElementType *x,AVLTree *T)
{
if(*T==  NULL)
{
*T=(AVLTree)malloc(sizeof(AVLTree));
if(*T==NULL)
printf("out of space");
else
{
(*T)->Date=*x;
(*T)->left=(*T)->right=NULL;
(*T)->Height=0;
}
}
else
{
if(*x<(*T)->Date)
{
(*T)->left=Insert(x,&((*T)->left));
if(Height((*T)->left)-Height((*T)->right)==2)
if(*x<((*T)->left->Date))
*T=SingleRotateLeft(*T);
else
*T=DoubleRotataeleft(*T);
}
else if(*x>(*T)->Date)
{
(*T)->right=Insert(x,&((*T)->right));
if(Height((*T)->right)-Height((*T)->left)==2)
if(*x>(*T)->left->Date)
*T=SingleRotateRight(*T);
else
*T=DoubleRotataeright(*T);
}

}
return *T;
}
AVLTree search_Tree(ElementType x,AVLTree T)
{
while(T)
{if(T->Date==x)
return T;
else if(x<T->Date)
search_Tree(x,T->left);
else
search_Tree(x,T->right);
}
return T;
}
void PreOrder(AVLTree T)//qianxubianli
{
if(T!=NULL)
{
printf("%d\n",T->Date);
PreOrder(T->left);
PreOrder(T->right);
}
}
void MiddleOrder(AVLTree T)
{
if(T!=NULL)
{
MiddleOrder(T->left);
printf("%d\n",T->Date);
MiddleOrder(T->right);
}
}
void PostOrder(AVLTree T)
{
if(T!=NULL)
{
PostOrder(T->left);
PostOrder(T->right);
printf("%d\n",T->Date);
}
}
int Max(int a,int b)
{
if(a>b)
return a;
else if(b>a)
return b;
else
return a;
}
int main()
{
AVLTree T=NULL;
AVLTree Q=NULL;
int a[]={3,2,1,4,5,6,7,16,15,14,13,12,11,10,8,9};
for(int i=0;i<16;i++)
Insert(&a[i],&T);
PreOrder(T);
printf("\n\n");
MiddleOrder(T);
system("pause");
}


原先没有输出结果是因为Insert()函数声明与调用指针方法不对,如代码

声明:AVLTree Insert(ElementType x,AVLTree T);
定义:
AVLTree Insert(ElementType x,AVLTree T)
{
if(T==  NULL)
{
T=(AVLTree)malloc(sizeof(AVLTree));
if(T==NULL)
printf("out of space");
else
{
T->Date=x;
T->left=T->right=NULL;
T->Height=0;
}
}
else
{
if(x<T->Date)
{
T->left=Insert(x,T->left);
if(Height(T->left)-Height(T->right)==2)
if(x<T->left->Date)
T=SingleRotateLeft(T);
else
T=DoubleRotataeleft(T);
}
else if(x>T->Date)
{
T->right=Insert(x,T->right);
if(Height(T->right)-Height(T->left)==2)
if(x>T->left->Date)
T=SingleRotateRight(T);
else
T=DoubleRotataeright(T);
}

}
T->Height=Max(Height(T->left),Height(T->right))+1;
return T;
}


因为这里的Insert()参数指针是拷贝了一份T的,这里参考一些别人的文章总结一下

      指针本身也是一个值,它的值是所指向对象的地址。指针传递参数本质上是值传递的方式,它所传递的是一个地址值。值传递过程中,被调函数的形式参数作为被调函数的局部变量处理,即在栈中开辟了内存空间以存放由主调函数放进来的实参的值,从而成为了实参的一个副本。值传递的特点是被调函数对形式参数的任何操作都是作为局部变量进行,不会影响主调函数的实参变量的值。

       而这里如果采用双重星号的方法,此时传递的不再是T指针的值,而是通过&T传递的T指针的地址,此时是参数是引用传递的,引用传递过程中,被调函数的形式参数虽然也作为局部变量在栈中开辟了内存空间,但是这时存放的是由主调函数放进来的实参变量的地址。被调函数对形参的任何操作都被处理成间接寻址,即通过栈中存放的地址访问主调函数中的实参变量。正因为如此,被调函数对形参做的任何操作都影响了主调函数中的实参变量。因此可以在函数中改变b指针的值,也就是指针指向的对象。

 
    可以看出,对指针取地址,函数定义的时候使用双重星号的作用不仅仅是为指针赋初始值,还可以在函数中改变指针指向哪个对象,而在普通的指针参数传递中,函数只能改变指针指向对象的值,不能改变指针具体指向哪个对象。

这里放一个二级指针使用的讲解:http://blog.csdn.net/bin510729392/article/details/51476327
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  指针 c语言