我写的二叉查找树可以编译运行,而且除了删除操作外,其他的操作(正文)
其他的操作都能正确执行,删除操作的问题是,在一次执行中,删除操作只能运行一次,第二次执行删除操作时,就会出现“0x00401351”指令引用的“0xdddddde1”内存,该内存不能为“read”
以下是源代码,源代码都有详细注释的:
程序代码:
#include<stdio.h> #include<stdlib.h> #define OK 1 #define ERROR 0 int N; //用来指示输入的数字的个数 typedef struct bstNode { int key; struct bstNode *lchild,*rchild; }BSTNode,*BSTree; void CreatTree(BSTree *root,int data[]) //创建二叉查找树 { BSTree p; //新建结点,用于接收malloc申请地址赋值 BSTree current; //当前结点 BSTree father; //父结点 int i; for(i=0;i<N;i++) { /*创建一个新结点,并指定结点内容,左子树和右子树置空*/ p=(BSTree)malloc(sizeof(BSTNode)); p->key=data[i]; //利用大for循环使主函数中的data数组的序号和创建结点的顺序同步 p->lchild=NULL; p->rchild=NULL; if(*root==NULL) *root=p; //根节点为空 else { current=(*root); //目前的位置在根结点 while(current != NULL) { father=current; //记录父结点 //当前结点数据大于等于输入数据,则此数据送往左子树 if(current->key >= data[i]) current = current->lchild; //当前结点数据小于输入数据,则此数据送往右子树 else current = current->rchild; } //连起父与子结点 if(father->key > data[i]) father->lchild = p; else father->rchild = p; } } } BSTree SearchBST(BSTree root,int key) { int counter=0; //查询次数计数器 BSTree p; p=root; while(p!=NULL) { counter++; if(p->key==key) { printf("查找次数为:%d\n",counter); return p; //查找成功,返回查找到的结点 } else { if(key < p->key) p=p->lchild; //在左子树中继续查找 else p=p->rchild; } } printf("查找次数为:%d\n",counter); return 0; //查找失败 } void InsertBST(BSTree *root,int key) //二叉排序树的插入 { BSTree p; BSTree father; BSTree current; p=(BSTree)malloc(sizeof(BSTNode)); p->key=key; p->lchild=NULL; p->rchild=NULL; if(*root==NULL) *root=p; else { current=(*root); while(current!=NULL) { father=current; if(key<(current->key)) current=current->lchild; else current=current->rchild; } if(key<(father->key)) //将current连接到p上 father->lchild=p; else father->rchild=p; } } void output(BSTree root) /*中序遍历输出二叉排序树,递归实现*/ { if(root!=NULL) { output(root->lchild); printf("%d ",root->key); output(root->rchild); } } int Delete(BSTree p) { //若删除的结点是叶子节点,直接根据指向叶子节点的指针变量p,用free(p)来删除叶子节点 //以下用if,else来选择处理删除的结点有一个孩子结点或有2个孩子结点的情况 BSTree q=NULL; BSTree s=NULL; if(!p->rchild && !p->lchild) { free(p); p=NULL; } else if(!p->rchild) //目标结点右子树为空,只需重接它的左子树 { q=p; p=p->lchild; free(q); q=NULL; } else if(!p->lchild) //目标结点左子树,只需重接他的右子树 { q=p; p=p->rchild; free(q); q=NULL; } else { q=p; s=p->lchild; while(s->rchild != NULL) { q=s; s=s->rchild; } //转左,然后向右到尽头 p->key = s->key; //s指向被删结点的中序序列的“前驱” //根据p的左孩子是否有右孩子来判断的 if(q!=p) //p的左孩子有右孩子,那么q就会从和p指向的同一结点处离开 q->rchild=s->lchild; //重接q的右子树 else q->lchild=s->lchild;//重接q的左子树 free(s); s=NULL; } return OK; } int DeleteBST(BSTree root,int key) { if(root==NULL) //树为空返回错误 return ERROR; else { while(root!=NULL) { if(key==root->key) return Delete(root); //找到要删除的元素后,传入指向目标元素的指针调用Delete函数 else if(key<(root->key)) root=root->lchild; else root=root->rchild; } return ERROR; } /*另一种else的写法 else { if(key==root->key) return Dlete(T); else if(key < root->lchild) return DeleteBST(root->lchild,key); else return DeleteBST(root->rchild,key); } */ } main() { int key,i,flag=1,select; int *data; BSTree root=NULL; BSTree p; printf("请输入要输入数据的个数:"); scanf("%d",&N); data=(int *)malloc(sizeof(int)*N); printf("输入树的数据(中间用空格隔开):\n"); for(i=0;i<N;i++) scanf("%d",data+i); printf("\n"); CreatTree(&root,data); //创建二叉查找树 /*创建的二叉查找树从小到大的排列*/ printf("二叉查找树从小到大的排列:"); output(root); /*-----------操作说明------------*/ printf("\n1.查询数据"); printf("\n2.插入数据"); printf("\n3.删除数据"); while(flag) { printf("输入要操作的序号:\n"); scanf("%d",&select); printf("\n"); switch(select) { case 1: printf("输入要查的数据值:\n"); scanf("%d",&key); p=SearchBST(root,key); if(p) printf("要查的数据是:%d\n",p->key); else printf("查无此数据\n"); break; case 2: printf("输入要插入的数据值:\n"); scanf("%d",&key); InsertBST(&root,key); /*创建的二叉查找树从小到大的排列*/ printf("插入成功之后二叉查找树从小到大的排列:"); printf("\n"); output(root); break; case 3: printf("\n请输入要删除的数据值:"); scanf("%d",&key); DeleteBST(root,key); output(root); break; } } }