- 使用 Spring Initializr 创建 Spring Boot 应用程序
- 在Spring Boot中配置Cassandra
- 在 Spring Boot 上配置 Tomcat 连接池
- 将Camel消息路由到嵌入WildFly的Artemis上
最近我又来更新这个系列了,其实感觉指针对于我们还是非常重要的存在。指针之所以是初学者们的“噩梦”,它的难度源于它的灵活性。
这篇文章,我想要来写一下指针的实际运用,如果指针只是一些考试的考题,那就没有意义了。最重要的,指针在C语言,乃至C++,都是不可或缺的一部分。
链表是一种数据结构。
对于一个链表来说,每个结点有两个域,即数据域和指针域,数据域是用来存放这个链表的数字,指针域用来存放下一个结点的地址。特别的,最后一个结点的指针域设为NULL。
这样,就不需要让整个链表顺序存储了。
对于数据的插入和删除操作,链表只需要新建结点即可:
插入和删除的时间复杂度是O(1),不需要移动元素。而对于普通的线性表,需要移动数据,因此时间复杂度为O(n)。
对于链表的结构体,我们可以这样写:
typedef struct List{
int data;
List *next;
List(int x){
this->data=x;
next=NULL;
}
};
List *lst;
data是数据域,next是指针域。
其中,List(x)是一个构造函数,这样在使用new进行结点分配的时候可以简便书写。分配的时候就需要这样写:
l=new List(x);
这个构造函数做了两件事:一个是把data进行赋值,一个是把next设为NULL。
补充1:this指针
其中,写this->data,this是指这个结构体本身,例如调用:
l=new List(x);
此时this就指向l。this是一个特殊的指针。有一种形象的比喻方式:
当你进入一个房子后,你可以看见桌子、椅子、地板等,但是房子你是看不到全貌了。
对于一个类的实例来说,你可以看到它的成员函数、成员变量,但是实例本身呢?
this是一个指针,它时时刻刻指向你这个实例本身。
当然,这里不写this也是可以的。这只是写法问题。
补充2:->运算符
这个运算符,我们一般称为“箭头运算符”。
假设我们有现在下面的一个结构体:
struct info{
string name;
int age;
}
如果现在有一个普通变量x,那么引用其中的age,写作:x.age
如果现在有一个指针变量p,那么引用其中的age,要写作p->age
也就是说,对于一个指针结构体,引用其中的成员需要使用->运算符。
本质上,p->age
等同于(*p).age
,注意这里括号虽然麻烦但是不可省略。箭头运算符只是一种简便写法。
我们知道,如果一个链表的当前结点为NULL,那么它必定是最后的结点。因此,我们可以采用递归的写法,如果链表当前节点不为NULL,那么就下一个结点。
void add(List *&l,int x){
if(l==NULL){
l=new List(x);
return;
}
else add(l->next,x);
}
l=new List(x);
,之前说过的构造函数写法。add(l->next,x)
表示找下一个结点。
补充3:*&是什么鬼!
如果懒得在原文找的话,我这里直接把原文贴出来了:
在这里,*表示指针,&表示引用传递,那么加在一起就是指针的引用传递,虽然声明看上去很烦,但是理解了也就是这么回事。
毫无难度的函数,我直接贴出来了,逻辑和add函数类似。
void write(List *l){
if(l==NULL)return;
else{
printf("%d ",l->data);
write(l->next);
}
}
链表的灵活之处就是它的插入和删除函数。
如下图所示,我们要在2之后插入一个10:
首先,我们需要把10和3连接起来,否则一旦断掉2和3之间的连接,那么整个链表就直接分离了,无法再找到3的位置。
下一步,就是把2和10连接起来,同时断开2和3的连接。
这样就把插入的操作完成了,其实本质是很简单了。
void insert(int pos,List *&l,int x){
if(pos==1){
List *p=new List(x);
p->next=l->next;
l->next=p;
}
else insert(pos-1,l->next,x);
}
为了找到待插入的位置pos,我们可以采用递归的方法,每往后一个结点pos-1,最终当pos=1时就到了想要的位置。
同样的链表,假设删除其中的3:
首先,先新建一个指针,指向3,否则后续操作过后就无法释放这块内存:
第二步,把2连接到4上面去。
最后,释放这个新建的指针,本质就是释放3。
代码还是一样,注意最终到pos=2就要停止了,这个算法无法删除首个结点的位置。
void remove(int pos,List *&l){
if(pos==2){
List *p=l->next;
l->next=l->next->next;
delete p;
}
else remove(pos-1,l->next);
}
一套完整的链表写下来也是有四五十行代码的,完整代码如下:
#include<bits/stdc++.h>
using namespace std;
typedef struct List{
int data;
List *next;
List(int x){
this->data=x;
next=NULL;
}
};
List *lst;
void add(List *&l,int x){
if(l==NULL){
l=new List(x);
return;
}
else add(l->next,x);
}
void write(List *l){
if(l==NULL)return;
else{
printf("%d ",l->data);
write(l->next);
}
}
void insert(int pos,List *&l,int x){
if(pos==1){
List *p=new List(x);
p->next=l->next;
l->next=p;
}
else insert(pos-1,l->next,x);
}
void remove(int pos,List *&l){
if(pos==2){
List *p=l->next;
l->next=l->next->next;
delete p;
}
else remove(pos-1,l->next);
}
int main(){
int n,m;
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++){
int x;
scanf("%d",&x);
add(lst,x);
}
while(m--){
int k;
scanf("%d",&k);
if(k==1){//插入操作
int pos,val;
scanf("%d%d",&pos,&val);
insert(pos,lst,val);
write(lst);putchar('\n');
}
else if(k==2){//删除操作
int pos;
scanf("%d",&pos);
remove(pos,lst);
write(lst);putchar('\n');
}
}
return 0;
}
服务架构进化论 原始分布式时代 一直以来,我可能和大多数的人认知一样,认为我们的服务架构的源头是单体架构,其实不然,早在单体系
序列化和反序列化相信大家都经常听到,也都会用, 然而有些人可能不知道:.net为什么要有这个东西以及.net frameword如何为我们实现这样的机制, 在这里我也是简单谈谈我对序列化和反序列化的
内容,是网站的核心所在。要打造一个受用户和搜索引擎关注的网站,就必须从网站本身的内容抓起。在时下这个网络信息高速发展的时代,许多低质量的信息也在不断地充斥着整个网络,而搜索引擎对一些高质量的内容
从第一台计算机问世到现在计算机硬件技术已经有了很大的发展。不管是现在个人使用的PC还是公司使用的服务器。双核,四核,八核的CPU已经非常常见。这样我们可以将我们程序分摊到多个计算机CPU中去计算,在
基本概念: 浅拷贝:指对象的字段被拷贝,而字段引用的对象不会被拷贝,拷贝对象和原对象仅仅是引用名称有所不同,但是它们共用一份实体。对任何一个对象的改变,都会影响到另外一个对象。大部分的引用类型,实
.NET将原来独立的API和SDK合并到一个框架中,这对于程序开发人员非常有利。它将CryptoAPI改编进.NET的System.Security.Cryptography名字空间,使密码服务摆脱
文件与文件流的区别(自己的话): 在软件开发过程中,我们常常把文件的 “读写操作” ,与 “创造、移动、复制、删除操作” 区分开来
1. 前言 单元测试一直都是"好处大家都知道很多,但是因为种种原因没有实施起来"的一个老大难问题。具体是否应该落地单元测试,以及落地的程度, 每个项目都有自己的情况。 本篇为
事件处理 1、事件源:任何一个HTML元素(节点),body、div、button 2、事件:你的操作 &
1、什么是反射? 反射 (Reflection) 是 Java 的特征之一,它允许运行中的 Java 程序获取自身的信息,并且可以操作类或对象的内部属性。 Oracle 官方对
1、源码展示 ? 1
Java 通过JDBC获得连接以后,得到一个Connection 对象,可以从这个对象获得有关数据库管理系统的各种信息,包括数据库中的各个表,表中的各个列,数据类型,触发器,存储过程等各方面的信息。
可能大家谈到反射面部肌肉都开始抽搐了吧!因为在托管语言里面,最臭名昭著的就是反射!它的性能实在是太低了,甚至在很多时候让我们无法忍受。不过不用那么纠结了,老陈今天就来分享一下如何来优化反射!&nbs
1. 前言 最近一段时间一直在研究windows 驱动开发,简单聊聊。 对比 linux,windows 驱动无论是市面上的书籍,视频还是社区,博文以及号主,写的人很少,导
问题:ifndef/define/endif”主要目的是防止头文件的重复包含和编译 ========================================================
不知不觉.Net Core已经推出到3.1了,大多数以.Net为技术栈的公司也开始逐步的切换到了Core,从业也快3年多了,一直坚持着.不管环境
以前面试的时候经常会碰到这样的问题.,叫你写一下ArrayList.LinkedList.Vector三者之间的区别与联系:原先一直搞不明白,不知道这三者之间到底有什么区别?哎,惭愧,基础太差啊,木
目录 @RequestParam(required = true)的误区 先说结论 参数总结 @RequestParam(r
目录 FTP、FTPS 与 SFTP 简介 FTP FTPS SFTP FTP 软件的主动模式和被动模式的区别
1、Visitor Pattern 访问者模式是一种行为模式,允许任意的分离的访问者能够在管理者控制下访问所管理的元素。访问者不能改变对象的定义(但这并不是强制性的,你可以约定为允许改变)。对管
我是一名优秀的程序员,十分优秀!