简体   繁体   English

在没有指针的情况下用 C 编写二叉搜索树

[英]writing a binary search tree in C without pointers

Is it possible to write a binary search tree in C without pointers?是否可以在没有指针的情况下用 C 编写二叉搜索树?

I have written using pointers as follows.我已经使用指针编写如下。

Working BST code in C using pointers使用指针在 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);
}

Is is possible to write a BST without pointers, and using Nodes only.是否可以在没有指针的情况下编写 BST,并且仅使用节点。 So, I want to access the left as node.left instead of node->left and so on.所以,我想以 node.left 而不是 node->left 等方式访问左侧。 Even the members of the structure node should be like甚至结构节点的成员也应该像

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

and the Node members would be declared as并且节点成员将被声明为

Node root; Node node;

and not as而不是作为

Node* root; Node* node;

If it's not possible to write BST using the above structures, why is it so?如果不能使用上述结构编写 BST,为什么会这样? Is it because, NULL is a pointer which has a value reserved for indicating that the pointer does not refer to a valid object.是不是因为,NULL 是一个指针,它具有一个保留值,用于指示该指针未引用有效对象。 So, if we were using just a structure, we wouldn't know when to stop.所以,如果我们只使用一个结构,我们不知道什么时候停止。 So, I commented out the NULL lines in the above code, and made changes to access as structure members and not pointers.因此,我注释掉了上面代码中的 NULL 行,并进行了更改以作为结构成员而不是指针访问。 I was expecting it to atleast compile, although it would be an infinite loop at places.我期待它至少可以编译,尽管它在某些地方会是一个无限循环。 However, it gives me some compilation errors as well.但是,它也给了我一些编译错误。

Tried BST code in C without using pointers, does not compile在不使用指针的情况下在 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);
}

However, I was going through how a binary search tree is implemented in Java, as follows.但是,我正在研究如何在 Java 中实现二叉搜索树,如下所示。 As seen below, members are accessed using the dot symbol.如下所示,使用点符号访问成员。 I'm curious to understand how it's done here.我很想知道它是如何在这里完成的。

If class is a structure, can I say that an object is a pointer to the structure.如果类是一个结构,我可以说一个对象是一个指向该结构的指针吗? The only difference being that in C, a pointer to a structure uses the notation -> to access the internal members of the structure, whereas, an object just uses .唯一的区别是在 C 中,指向结构的指针使用符号 -> 来访问结构的内部成员,而对象仅使用 . to access the internal memebers of the structure(class)访问结构(类)的内部成员

Working BST code in java, which uses the .在 Java 中工作的 BST 代码,它使用 . notation, got me thinking on how I can emulate this in C to use the .符号,让我思考如何在 C 中模拟它以使用 . symbol and not ->符号而不是 ->

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

In stead of pointers to memory objects, you can allocate a large array of Node objects and store indexes into this array in the left and right members.在指针代替内存对象,可以分配一个大阵列的Node对象和存储索引到这个阵列中的leftright的成员。

Array entry 0 is the root node.数组条目0是根节点。 You must keep track of the first unused array element to store a new Node .您必须跟踪第一个未使用的数组元素来存储新的Node You can use calloc to allocate the array and realloc to enlarge the array.您可以使用calloc来分配数组并使用realloc来扩大数组。

You must keep track of deleted items: keep track of the first one and put in left the index of the next deleted item (kind of linked list).您必须跟踪已删除的项目:跟踪第一个项目并将下一个已删除项目的索引(一种链表)放入left You can also keep track of the last deleted item to quickly append another deleted iem to the list.您还可以跟踪最后删除的项目以快速将另一个已删除的项目附加到列表中。

You can implement binary search in an array, using array indexes instead of pointers.您可以使用数组索引而不是指针在数组中实现二分查找。 In C the array is just a language construct that automates pointer arithmetic and keeps it out of your code.在 C 中,数组只是一种语言结构,可以自动执行指针运算并将其排除在您的代码之外。 If you malloc the entire array of structs and make the left and right members integers of some appropriate size, it can work.如果您对整个结构数组进行 m​​alloc 并将左右成员设置为适当大小的整数,则它可以工作。

But in structs created individually with malloc you can't do it without pointers because...但是在用 malloc 单独创建的结构中,没有指针就不能这样做,因为......

In C the structure is just memory allocated in a contiguous block.在 C 中,结构只是在连续块中分配的内存。 The .这 。 operator translates to a simple offset from the beginning of a block.运算符转换为从块开头的简单偏移量。

When you try to use the .当您尝试使用 . operator to refer to .left or .right you are referring to a different struct that you created with a different malloc and it could be anywhere in heap memory.运算符来引用 .left 或 .right 您指的是使用不同 malloc 创建的不同结构,它可以位于堆内存中的任何位置。 So the simple offset from the beginning of the current node is unknown.所以从当前节点开始的简单偏移量是未知的。

So in C you need a pointer, to store the address of the left or right node.所以在 C 中你需要一个指针来存储左节点或右节点的地址。

In Java these are object references, essentially nicely wrapped and managed pointers.在 Java 中,这些是对象引用,本质上很好地包装和管理指针。 The JVM is managing allocation and tracking memory addresses, and this is mostly transparent to your code. JVM 正在管理分配和跟踪内存地址,这对您的代码来说基本上是透明的。 You are, in effect, using pointers in the Java code, at run-time but your source code is written in terms of object references.实际上,您是在运行时在 Java 代码中使用指针,但您的源代码是根据对象引用编写的。

You could also implement binary search in C using a file or memory mapped file, using offsets into that file instead of C pointers.您还可以使用文件或内存映射文件在 C 中实现二进制搜索,使用该文件的偏移量而不是 C 指针。 This is probably not what you intend in your question, but is/was often done in applications with large sorted data sets that need binary search.这可能不是您在问题中的意图,但是在需要二分搜索的大型排序数据集的应用程序中经常这样做。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM