2015-10-18 73 views
1

是否有可能用C编写一个二叉搜索树而没有指针?用C编写一个二叉搜索树没有指针

我写过使用指针如下。通过在C

工作BST代码指针

#include <stdio.h> 
#include <malloc.h> 

typedef struct node 
{ 
int data; 
struct node* left; 
struct node* right; 
}Node; 
Node* root = NULL; 

int insert(int); 
int display(Node*); 

int main(void) 
{ 
int n = 0; 

while(1) 
{ 
    printf("Enter data : "); 
    scanf("%d",&n); 

    if(n == -1) 
    break; 

    insert(n); 
} 

display(root); 

return 0; 
} 

int insert(int data) 
{ 
Node* node = malloc(sizeof(Node)); 
node->data = data; 
node->left = NULL; 
node->right = NULL; 
Node* parent; 
Node* trav; 

if(root == NULL) 
    root = node; 
else 
{ 
    trav = root; 

    while(trav != NULL) 
    { 
    parent = trav; 

    if(node->data < trav->data) 
    trav = trav->left; 
    else 
    trav = trav->right; 
    } 

    if(node->data < parent->data) 
    parent->left = node; 
    else 
    parent->right = node; 
} 
} 

int display(Node* node) 
{ 
if(node == NULL) 
    return 0; 

display(node->left); 
printf("%d ",node->data); 
display(node->right); 
} 

是可以编写一个BST没有指针,只有使用节点。所以,我想以node.left的形式访问左侧,而不是node-> left,等等。结构节点连成员应该像

typedef struct node 
    { 
    int data; 
    struct node left; 
    struct node right; 
    }Node; 

和节点成员将被宣布为

Node root; Node node; 

,而不是作为

Node* root; Node* node; 

如果这是不可能的BST使用写上述结构,为什么如此?是因为,NULL是指针,它有一个值保留,用于指示指针不引用有效对象。所以,如果我们只使用一个结构,我们就不知道何时停止。所以,我在上面的代码中注释了NULL行,并且改变了访问结构成员而不是指针。我期待它能够尽快编译,尽管它会在各个地方形成一个无限循环。但是,它也给我一些编译错误。用C

尝试BST代码,而无需使用指针,不编译

#include <stdio.h> 
#include <malloc.h> 

typedef struct node 
{ 
int data; 
struct node left; 
struct node right; 
}Node; 
//Node root = NULL; 
Node root; 

int insert(int); 
int display(Node); 
int rootformed = 0; 

int main(void) 
{ 
int n = 0; 

while(1) 
{ 
    printf("Enter data : "); 
    scanf("%d",&n); 

    if(n == -1) 
    break; 

    insert(n); 
} 

display(root); 

return 0; 
} 

int insert(int data) 
{ 
Node node = malloc(sizeof(Node)); 
node.data = data; 
node.left = NULL; 
node.right = NULL; 
Node parent; 
Node trav; 

if(rootformed == 0) 
{ 
    root = node; 
    rootformed = 1; 
} 
else 
{ 
    trav = root; 

    //while(trav != NULL) 
    while(1) 
    { 
    parent = trav; 

    if(node.data < trav.data) 
    trav = trav.left; 
    else 
    trav = trav.right; 
    } 

    if(node.data < parent.data) 
    parent.left = node; 
    else 
    parent.right = node; 
} 
} 

int display(Node node) 
{ 
//if(node == NULL) 
    //return 0; 

display(node.left); 
printf("%d ",node.data); 
display(node.right); 
} 

不过,我正在经历二叉搜索树是如何在Java中实现,如下所示。如下所示,使用点符号访问成员。我很想知道它是如何完成的。

如果class是一个结构,我可以说一个对象是一个指向 结构的指针。唯一的区别是在C中,指向 结构的指针使用符号 - >来访问 结构的内部成员,而对象只是使用该符号。访问结构(类)的内部 承包商,客人

工作BST代码在Java中,其使用。符号,让我想到如何在C中模拟这个使用。符号和不 - >

public class BinarySearchTree 
{ 
    public Node root; 
    public BinarySearchTree() 
    { 
     this.root = null; 
    } 

    public boolean find(int id) 
    { 
     Node current = root; 
     while(current!=null) 
     { 
      if(current.data == id) 
      { 
       return true; 
      } 
      else if(id < current.data) 
      { 
       current = current.left; 
      } 
      else 
      { 
       current = current.right; 
      } 
     } 

     return false; 
    } 

    public boolean delete(int id) 
    { 
     Node parent = root; 
     Node current = root; 
     boolean isLeftChild = false; 

     while(current.data != id) 
     { 
      parent = current; 
      if(id < current.data) 
      { 
       isLeftChild = true; 
       current = current.left; 
      } 
      else 
      { 
       isLeftChild = false; 
       current = current.right; 
      } 
      if(current ==null) 
      { 
       return false; 
      } 
     } 
     //if i am here that means we have found the node 
     //Case 1: if node to be deleted has no children 
     if(current.left==null && current.right==null) 
     { 
      if(current==root) 
      { 
       root = null; 
      } 
      if(isLeftChild ==true) 
      { 
       parent.left = null; 
      } 
      else 
      { 
       parent.right = null; 
      } 
     } 
     //Case 2 : if node to be deleted has only one child 
     else if(current.right==null) 
     { 
      if(current==root) 
      { 
       root = current.left; 
      } 
      else if(isLeftChild) 
      { 
       parent.left = current.left; 
      } 
      else 
      { 
       parent.right = current.left; 
      } 
     } 
     else if(current.left==null) 
     { 
      if(current==root) 
      { 
       root = current.right; 
      } 
      else if(isLeftChild) 
      { 
       parent.left = current.right; 
      } 
      else 
      { 
       parent.right = current.right; 
      } 
     } 
     else if(current.left!=null && current.right!=null) 
     { 
      //now we have found the minimum element in the right sub tree 
      Node successor = getSuccessor(current); 
      if(current==root) 
      { 
       root = successor; 
      } 
      else if(isLeftChild) 
      { 
       parent.left = successor; 
      } 
      else 
      { 
       parent.right = successor; 
      }   
      //successor.left = current.left; 
     }  
     return true;   
    } 

    public Node getSuccessor(Node deleteNode) 
    { 
     Node successsor =null; 
     Node successsorParent =null; 
     Node current = deleteNode.right; 
     while(current!=null) 
     { 
      successsorParent = successsor; 
      successsor = current; 
      current = current.left; 
     } 
     //check if successor has the right child, it cannot have left child for sure 
     //if it does have the right child, add it to the left of successorParent. 
     //successsorParent 
     if(successsor!=deleteNode.right) 
     { 
      successsorParent.left = successsor.right; 
      successsor.right = deleteNode.right; 
     } 

     if(successsor==deleteNode.right) 
     { 
      /* Then no more right tree */ 

     } 

     successsor.left = deleteNode.left; 
     return successsor; 
    } 

    public void insert(int id) 
    { 
     Node newNode = new Node(id); 
     if(root==null) 
     { 
      root = newNode; 
      return; 
     } 
     Node current = root; 
     Node parent = null; 
     while(true) 
     { 
      parent = current; 
      if(id < current.data) 
      {    
       current = current.left; 
       if(current==null) 
       { 
        parent.left = newNode; 
        return; 
       } 
      } 
      else 
      { 
       current = current.right; 
       if(current==null) 
       { 
        parent.right = newNode; 
        return; 
       } 
      } 
     } 
    } 

    public void display(Node root) 
    { 
     if(root != null) 
     { 
      display(root.left); 
      System.out.print(" " + root.data); 
      display(root.right); 
     } 
    } 

    public static void main(String arg[]) 
    { 
     BinarySearchTree b = new BinarySearchTree(); 

     b.insert(3);b.insert(8); 
     b.insert(1);b.insert(4);b.insert(6);b.insert(2);b.insert(10);b.insert(9); 
     b.insert(20);b.insert(25);b.insert(15);b.insert(16); 

     System.out.println("Original Tree : "); 
     b.display(b.root);  
     System.out.println(""); 
     System.out.println("Check whether Node with value 4 exists : " + b.find(4)); 
     System.out.println("Delete Node with no children (2) : " + b.delete(2));   
     b.display(root); 
     System.out.println("\n Delete Node with one child (4) : " + b.delete(4));  
     b.display(root); 
     System.out.println("\n Delete Node with Two children (10) : " + b.delete(10));  
     b.display(root); 
    } 
} 

class Node 
{ 
    int data; 
    Node left; 
    Node right; 

    public Node(int data) 
    { 
     this.data = data; 
     left = null; 
     right = null; 
    } 
} 
+0

您可以使用数组,为null链接保留索引“-1”。如何回收已删除的项目?通过有可用节点的第二个“链接列表”。 –

+0

@WeatherVane,谢谢你。就像我上面提到的那样,想要了解整个指针/地址概念是如何在Java中引发的。所以,如果类是一个结构,我可以说一个对象是一个指向结构的指针。唯一的区别是在C中,指向结构的指针使用符号 - >来访问结构的内部成员,而对象只是使用。访问结构(类) – PepperBoy

回答

3

在指针代替存储器对象,可以分配一个大阵列Node对象和存储索引的这个阵列中的leftright成员。

数组条目0是根节点。您必须跟踪第一个未使用的数组元素来存储新的Node。您可以使用calloc来分配数组,并使用realloc来放大数组。

您必须跟踪已删除的项目:跟踪第一个项目,并在left中输入下一个已删除项目(链接列表的种类)的索引。您还可以跟踪上次删除的项目,以便快速将另一个已删除的iem附加到列表中。

+0

的内部memebers感谢您的方法。只是想确认一下,我在上面提到的关于java的部分中提到过,希望知道它是如何完成的。所以,如果类是一个结构,我可以说一个对象是一个指向结构的指针。唯一的区别是在C中,指向结构的指针使用符号 - >来访问结构的内部成员,而对象只是使用。访问结构的内部成员(类) – PepperBoy

0

您可以使用数组索引而不是指针来实现数组中的二分搜索。在C中,数组只是一种语言结构,它可以自动执行指针运算并将其保留在代码之外。如果你malloc整个数组的结构,并使一些适当的大小的左侧和右侧成员整数,它可以工作。

但在使用malloc单独创建结构,你不能这样做没有指针,因为......

在C结构是在一个连续的块中分配内存只。这个。运算符转换为从块的开始处的简单偏移量。

当您尝试使用。运算符引用.left或.right您指的是您使用不同的malloc创建的不同结构,它可能位于堆内存中的任何位置。所以从当前节点开始的简单偏移是未知的。

所以在C中,您需要一个指针来存储左侧或右侧节点的地址。

在Java中,这些是对象引用,本质上是很好的包装和管理指针。 JVM正在管理分配和跟踪内存地址,这对您的代码来说通常是透明的。实际上,您在运行时使用Java代码中的指针,但是您的源代码是根据对象引用编写的。

您还可以使用文件或内存映射文件在C语言中实现二进制搜索,使用偏移量代替C指针指向该文件。这可能不是你想要的问题,但是/经常在具有需要二进制搜索的大型分类数据集的应用程序中完成。