在没有指针的情况下在C中编写二进制搜索树

时间:2015-10-18 18:46:23

标签: java c oop pointers binary-search-tree

是否可以在没有指针的情况下在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-&gt; left来访问左边,依此类推。甚至结构节点的成员也应该像

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

并且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中,指向a的指针   结构使用符号 - &gt;访问的内部成员   结构,而一个对象只是使用。访问内部   结构的成员(班级)

使用java中的工作BST代码。让我思考如何在C语言中使用它来表达。符号而不是 - &gt;

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;
    }
}

2 个答案:

答案 0 :(得分:3)

除了指向内存对象的指针外,您还可以在Nodeleft成员中分配大量right个对象并将索引存储到此数组中。

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

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

答案 1 :(得分:0)

您可以使用数组索引而不是指针在数组中实现二进制搜索。在C中,数组只是一种语言结构,可以自动执行指针算法并使其不受代码限制。如果你对整个结构数组进行malloc并使左右成员整数具有一些合适的大小,它就可以工作。

但是在使用malloc单独创建的结构中,你无法在没有指针的情况下完成它,因为......

在C中,结构只是在连续块中分配的内存。的。运算符转换为块开头的简单偏移量。

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

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

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

您还可以使用文件或内存映射文件在C中实现二进制搜索,使用偏移到该文件而不是C指针。这可能不是您在问题中的意图,但通常是在需要二进制搜索的大型排序数据集的应用程序中完成的。