I'm working on a homework assignment in C and I think that a binary search tree would be the best way to implement my solution. The problem is we aren't allowed to define structs or any compound data types, so no
struct TreeNode {
struct TreeNode* parent;
struct TreeNode* left;
struct TreeNode* right;
int key;
int value;
}
or anything like that.
The tree will have to be entirely implemented wit开发者_高级运维h pointers, so I've been trying to define a number of macros to make navigating and editing the tree easier, such as this one to get a pointer to the parent of a node (where the pointers are void pointers):
#define PARENT(ptr) *(void *)(ptr+ALIGNMENT)
The problem, of course, is that you can't dereference void pointers. My question is: if you have a void pointer to a location in memory where another void pointer is stored, how can you read that stored pointer.
Or if that's impossible, is there a better way to do this tree?
Represent the nodes as an array and use pointer arithmetic to access the left and right nodes of a given node. For example, the numeric sequence 4, 3, 7, 1, 6 is stored in a binary tree:
4
/ \
3 7
/ \
1 6
if you choose to represent this tree using an array, the position of the left child of a node at position C
is 2 * C
and its right node is at 2 * C + 1
. In our example, the number 3
is at the second
position. Its left child is at 2 * 2
, i.e at the fourth
position and the right child is at 2 * 2 + 1
, i.e at the fifth position:
values: 4 3 7 1 6
positions: 1st 2nd 3rd 4th 5th
The following sample code shows how to walk an array based binary tree. You can figure out how to insert new values into the tree (using the above formulas), how to dynamically grow the array, how to use pointer arithmetic to access child nodes etc:
#include <stdio.h>
#define ARRAY_SIZE 5
static int btree[ARRAY_SIZE];
static void fill_btree ();
static void walk_btree ();
int
main ()
{
fill_btree ();
walk_btree ();
return 0;
}
static void
fill_btree ()
{
btree[0] = 4;
btree[1] = 3;
btree[2] = 7;
btree[3] = 1;
btree[4] = 6;
}
static int
pos (int i)
{
return ((i + 1) * 2);
}
static void
walk_btree ()
{
int i;
for (i = 0; i < ARRAY_SIZE; ++i)
{
int p = pos(i);
int root = btree[i];
int left = ((p - 1) < ARRAY_SIZE) ? btree[p-1] : 0;
int right = (p < ARRAY_SIZE) ? btree[p] : 0;
printf ("root: %d, left: %d, right: %d\n", root, left, right);
}
}
Here is a way to handle your pointers. I didn't write your whole tree (you can do that), but here is a way to manage your pointer "structure" without using a real structure. This doesn't build a tree for you, it just shows how you would create "faux" nodes and manage the pointers in memory.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
unsigned int *newNode();
int main() {
unsigned int *root;
unsigned int *data;
unsigned int *left, *right;
unsigned int *nodeA, *A, *nodeB, *B;
/* get a 12 byte root node */
root = newNode();
printf("root: %p\n", root);
/* Setup root node. Each is an offset unsigned into the 12 bytes in the faux node */
data = root;
left = root + 1;
right = root + 2;
/* create a NEW 12 byte child node and assign it to the root left child */
nodeA = newNode();
memcpy(left,&nodeA,sizeof(unsigned int));
printf("NodeA ptr (left child root): %p\n", nodeA);
/* create a NEW 12 byte child node and assign it to the root right child */
nodeB = newNode();
memcpy(right,&nodeB,sizeof(unsigned int));
printf("NodeB ptr (right child root): %p\n", nodeB);
/* what are my pointers? */
A = (unsigned int *)*(root + 1); /* root left node is pointing to child nodeA */
B = (unsigned int *)*(root + 2); /* root right node is pointing to child nodeB */
printf("A: %p, B: %p\n", A, B);
/*
* hopefully from this you can see the recursive nature of it and how
* you would build the tree using these pointer allocations and assignments
*/
/*
* This is not meant to be a full working application. I did not free any
* of these mallocs. You have to free up your memory when the program
* finishes. This was just to show how to go about making nodes
*/
return(0);
}
/*
* allocates 12 bytes to hold three unsigned integers, one to some data stream
* one for the left node, one for the right node
*
* |--data--|--left--|--right--| (each block is a four byte unsigned int)
*
*/
unsigned int *newNode() {
/* Allocates 12 bytes to store 3 unsigned integer values */
unsigned int *ptr = (unsigned int *)malloc(sizeof(unsigned int) * 3);
memset(ptr,0,sizeof(unsigned int) * 3);
return(ptr);
}
精彩评论