c c++ 指针做参数传递与使用,猿辅导2017笔试题

6 篇文章 0 订阅
5 篇文章 0 订阅

1 c c++指针的使用方法在这道题中有很好体现,不仅有指针还有指针的指针,即LinkNode **root.

规则,如下:

1. 可以把变量,指针,指针的指针当做三层,*号是退层,&是进层(&主要用在传参数的时候)。这样可以把所有有关的指针变量转换为 LinkNode LinkNode* LinkNode** 这三类。                                          
2. 这三类中,不论形式参数是**root, 还是*root,还是root,实参都无法在子函数中改变,只有形参才会变化。
3.形参和实参形式的确定: 如果想用指针,不论是哪种类型,*root 还是**root,主函数中的实参一般都定义为*root,定义为**root会不断报错。而形式参数一般根据是否需要改变指针来确定是否需要用**root,和主函数的实参形式无关。
4. 如果使用*root做参数时发现需要对root进行修改,那么就需要用到**root了。
5. 指针运算符->与*具有同样的作用。
6. *运算符的运算级别比->弱,所以需要加上(),即(*root)->value =  7;
7. 可以结合这个题的代码来理解以上规则。

具体题目见下面:
https://www.nowcoder.com/question/next?pid=11727202&qid=218378&tid=20369002
题目描述

翻转一个环形的链表,下面给出LinkNode数据结构和需要实现的函数。(环形链表没有头指针,即空链表用NULL/null表示)。


// C/C++
struct LinkNode {
     int   value;
     LinkNode * next
};
 
void reverse(LinkNode * root) {
       //   TODO
}
 
// Java
public class LinkNode {
       private int value;
       private LinkNode next;
}
 
public void reverse(LinkNode root) {
       // TODO
}

我的思路:一种方法是借助vector数组来翻转,另外一种方法是就地逆置,即空间复杂度为O(1),方法是把节点都摘下来,然后按照头插法再重建一次,由于要用到头插法,所以初始化的时候就新建了头指针,然后把第一个节点当做头结点来做具体可以见我的图示。两种方法的时间复杂度都是O(n).

// ConsoleApplication1.cpp : 定义控制台应用程序的入口点。
//

#include "stdafx.h"
#include <stdio.h>
#include <stdlib.h>
#include <algorithm>
#include <string.h>
#include <string>
#include <math.h>
#include <map>
#include <vector>

using namespace std;

struct LinkNode {
	int value;
	LinkNode* next;
};

void InitList(LinkNode **L) {
	*L = (LinkNode*)malloc(sizeof(LinkNode));//malloc的返回参数是指针类型的,应该用指针类型对其强制转化。
	(*L)->next = *L;
	return;
}

void CreatList(LinkNode* root) {
	LinkNode *p, *s;
	p = root;//尾插法,把p当做尾节点
	int tp = 0;
	scanf("%d", &p->value);
	while (scanf("%d",&tp) != EOF) {
		s = (LinkNode*)malloc(sizeof(LinkNode));
		s->value = tp;
		p->next = s;
		p = s;
	}
	s->next = root;
	return;
}

void ListReverse(LinkNode *root) {
	vector<int> v;
	LinkNode *p = root->next;
	v.push_back(root->value);
	while (p != root) {
		v.push_back(p->value);
		p = p->next;
	}
	for (int i = 0;i < v.size();i++) {
		p->value = v[v.size() - i -1];
		p = p->next;
	}
	return;
}

void ListReverse1(LinkNode **root) {
	LinkNode *root1 = (LinkNode*)malloc(sizeof(LinkNode));
	root1->next = *root;
	
	LinkNode *tp = (*root)->next;
	LinkNode *p = tp->next;//显然*和->具有同样的作用,即*p和->next 是同一种类型的变量。
	(*root)->next = NULL;
	do {
		tp->next = root1->next;
		root1->next = tp;
		tp = p;
		p = p->next;
	} while (tp != *root);
	(*root)->next= root1->next;//显然*root和root1才是同一种类型的。
	*root = root1->next;/*从主函数传参到子函数,无论将形参声明为*,还是** 都无法对指针变量进行改变。
显然,指针运算符->和*的功能很相近,这也是虽然无法对指针变量修改,但却可以对next域进行修改的原因。*/
	return;
}

void ListReverse2(LinkNode *root) {
	root = root->next;
	return;
}

void PrintList(LinkNode *root) {
	LinkNode *p = root;
	do {
		printf("%d ",p->value );
		p = p->next;
	} while (p != root);
	return;
}

void change(int *a) {
	int *c = (int *)malloc(sizeof(int));
	*c = 5;
	a = c;
}



int main()
{
	freopen("Text.txt", "r", stdin);
	LinkNode* root;//不要定义为LinkNode** root,无论怎么传参,或者在主函数中初始化都会在进入InitList时报错
	InitList(&root);
	CreatList(root);
	PrintList(root);
	ListReverse1(&root);
	//ListReverse2(*root);
	PrintList(root);
    return 0;
}


第二种方法的图解:
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值