C数据结构设计中,表首结点和二叉树根结点的头指针——传指针还是传指针的指针?

        在链表中添加节点,为什么AddToTail(ListNode** pHead,int value)的第一个形参是指向节点指针的指针??

        书上的解释如下:第一个参数pHead是一个指向指针的指针,当向一个空链表插入一个节点时,新插入的节点是链表的头指针,此时会改动头指针,因此必须把pHead参数设置为指向指针的指针。

        总的来说这样做的目的是为了应对“空链表”的情况。为了防止往一个空链表中插入一个结点时,新插入的结点那就是链表的头指针,这时如果链表的结点是一级指针的话,那么出了链表插入函数的作用域后,头结点又回到了原来的空值。

        看着解释似懂非懂,源代码如下;

struct ListNode{
	int data;
	ListNode* m_pNext;
};
void AddToTail(ListNode** pHead, int value)
{
	ListNode* p_newNode = new ListNode();
	p_newNode->data = value;
	p_newNode->m_pNext = NULL;

	//先判断有没有头结点
	if (pHead == NULL)
	{
		*pHead = p_newNode;
	}
	else
	{
		ListNode* pNode = *pHead;

		while (pNode->m_pNext != NULL)//找到尾节点
			pNode = pNode->m_pNext;

		pNode->m_pNext = p_newNode;//连接节点
	}
}

        在C++中,以传值的形式作为参数的变量在函数体内被修改之后,出了函数体就会失效,准确的说这个变量没有被修改过,因此需要传入该变量的指针或者使用引用传参的方式。现在测试传入的形参是ListNode* pHead时会出现什么情况;代码如下:

#include <iostream>  
#include <string>  
using namespace std;
struct ListNode
{
	int value;
	ListNode* next;
};

void AddToTail(ListNode* pHead, int value) 
{
	ListNode* pNew = new ListNode();
	pNew->value = value;
	pNew->next = NULL;

	if (pHead == NULL) 
		pHead = pNew;
	else 
	{
		ListNode* pNode = pHead;

		while (pNode->next != NULL) 
			pNode = pNode->next;

		pNode->next = pNew;
	}
}
int main()
{
	ListNode* head = NULL;
	AddToTail(head, 10);
	if (head != NULL) {
		cout << head->value << endl;
	}
	else {
		cout << "head==NULL" << endl;
	}
	return 0;
}
        结果是:head==NULL,这时可以看到如果链表的结点是一级指针的话,那么出了链表添加节点的函数后,头结点又回到了原来的空值。

        head本身就是指针,传入函数后生成指针副本,修改这个副本不会对head发生实质变化,只有传入head的指针才会起到修改head的作用,这和传值相同,这里的形式咋一看是传指针实质是“传值”,但是没有通过head更深一层指针去修改它的内容,所以head不会发生改变。



### 回答1: 如果使用二叉链表作为储存结构,那么每个结点应该包含三个域:左孩子指针、右孩子指针和双亲指针。因此,如果要获取某个结点x的双亲,只需要访问x的双亲指针即可。 假设我们已经定义了二叉树结点的结构体如下: ``` struct BinaryTreeNode { int value; // 结点的值 BinaryTreeNode* left; // 左孩子指针 BinaryTreeNode* right; // 右孩子指针 BinaryTreeNode* parent; // 双亲指针 }; ``` 那么获取结点x的双亲代码如下: ``` BinaryTreeNode* getParent(BinaryTreeNode* x) { if (x == nullptr || x->parent == nullptr) { // 如果x为空或x没有双亲,返回空指针 return nullptr; } else { // 返回x的双亲指针 return x->parent; } } ``` 调用该函数,结点x,即可获取x的双亲。例如,假设我们已经构建好了一棵二叉树,其结点A是节点,结点B和结点C是它的左右孩子,结点D是结点B的左孩子,结点E是结点C的右孩子。如果我们要获取结点D的双亲,可以这样调用函数: ``` BinaryTreeNode* root = ...; // 节点A BinaryTreeNode* d = ...; // 结点D BinaryTreeNode* parent = getParent(d); if (parent != nullptr) { cout << "结点D的双亲是:" << parent->value << endl; } else { cout << "结点D没有双亲或者输入的结点为空" << endl; } ``` ### 回答2: 二叉链表是一种常用的二叉树存储结构。在二叉链表,每个结点除了包含数据元素外,还包含了指向其左孩子和右孩子的指针。而结点的双亲可以通过在结点结构添加一个指向父结点指针来表示。 具体实现时,可以在结点结构添加一个指针变量parent,用于指向结点的父结点。当需要访问结点x的双亲时,可以通过访问x的parent指针来获取。 例如,下面是一个二叉链表结点的定义: ```c typedef struct Node { int data; // 结点存储的数据元素 struct Node* left; // 指向左孩子的指针 struct Node* right; // 指向右孩子的指针 struct Node* parent; // 指向父结点指针 } Node; ``` 假设有一个指向二叉树结点指针root,要访问结点x的双亲,可以使用以下代码: ```c Node* getParent(Node* root, Node* x) { if (root == NULL || root == x) { return NULL; // 结点或目标结点为空时,返回NULL } if (root->left == x || root->right == x) { return root; // 如果目标结点是当前结点的左孩子或右孩子,则当前结点就是目标结点的双亲 } Node* parent = getParent(root->left, x); if (parent != NULL) { return parent; // 如果在左子树找到双亲,直接返回 } return getParent(root->right, x); // 否则在右子树找双亲 } ``` 以上代码使用递归方式实现了获取结点x的双亲的功能。当结点为空或结点就是目标结点x时,返回NULL。在每个结点,分别判断左孩子和右孩子是否为目标结点x,如果是,则返回当前结点;如果不是,则递归地在左子树和右子树继续寻找。这样,就可以通过二叉链表来实现获取二叉树任意结点双亲的功能。 ### 回答3: 在二叉链表,每个结点都有一个指针指向其双亲结点。假设我们有一个二叉树的二叉链表储存结构如下: ```c typedef struct BiTNode { ElemType data; // 结点数据 struct BiTNode *lchild, *rchild; // 左子结点和右子结点指针 struct BiTNode *parent; // 双亲结点指针 } BiTNode, *BiTree; ``` 为了找到结点x的双亲,我们可以进行如下操作: 1. 判断二叉树是否为空,如果为空则返回空。 2. 从结点开始,从上至下按层遍历二叉树。 3. 在遍历的过程,判断当前结点的左子结点和右子结点是否为x,如果是则返回该结点作为x的双亲。 4. 如果当前结点的左子结点和右子结点不是x,则将当前结点入队,并依次遍历其左子结点和右子结点。 5. 重复步骤3和4,直到找到结点x的双亲或者遍历完整个二叉树。 要实现上述操作,我们可以使用队列作为辅助数据结构,即在操作过程结点依次入队,然后依次出队。 以下是一种可能的C语言实现: ```c BiTNode* FindParent(BiTree root, BiTNode* x) { if (root == NULL || x == NULL) { return NULL; } queue<BiTNode*> q; // 辅助队列 q.push(root); // 结点入队 while (!q.empty()) { BiTNode *curNode = q.front(); // 取出队列结点 q.pop(); // 出队 // 判断左子结点或右子结点是否为x,是则返回当前结点 if (curNode->lchild == x || curNode->rchild == x) { return curNode; } // 将左子结点和右子结点入队 if (curNode->lchild) { q.push(curNode->lchild); } if (curNode->rchild) { q.push(curNode->rchild); } } return NULL; // 遍历完整个二叉树都没找到x的双亲,则返回NULL } ``` 通过以上实现,我们可以找到任意一个二叉树结点x的双亲结点
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值