数据结构和算法-单链表

数据结构和算法-单链表

1. 链表介绍

  链表是有序的列表,但是它在内存中是存储如下

在这里插入图片描述

图1 单链表示意图

小结:

  1. 链表是以节点的方式存储
  2. 每个节点包含data域,next域,指向下一个节点。
  3. 如图:发现链表的各个节点不一定是连续存储。比如地址为150的节点下一个节点的地址不为160,而是指向地址为110的节点。
  4. 链表分带头节点的链表没有头节点的链表,根据实际的需求来确定。

单链表(带头结点)逻辑结构示意图如下

在这里插入图片描述

图2 带头结点的单链表

注意:图2中逻辑结构的连接并不是按照地址的顺序画的,而是按照每个节点的next域的内存地址连接的。真实的内存存储世图1所示

2. 单链表的应用实例

使用带head头的单向链表实现-水浒英雄排行榜管理

  1. 完成对英雄人物的增删改查操作,注:删除和修改,查找。
  2. 第一种方法在添加英雄时,直接添加到链表尾部
  3. 第二种方法在添加英雄时,根据排名将英雄插入到指定位置(如果有这个排名,则添加失败,并给出提示)

思路:使用一个类来代表一个节点 其中类中的属性来表示节点中的内容

  • 添加(创建)
    • 先创建一个head节点,作用就是表示单链表的头
    • 后面每添加一个节点,就直接加入到链表的最后
  • 遍历
    • 通过一个辅助变量遍历,帮助遍历整个链表
class HeroNode{int no;String name;String nickName;HeroNode next;
}

在这里插入图片描述

图3 单链表的创建示意图

2.1 直接将节点添加到链表尾部

实现添加节点时,直接添加到链表尾部

public class SingleLinkedListDemo {public static void main(String[] args) {//进行测试//先创建节点HeroNode heroNode1 = new HeroNode(1, "松江", "及时雨");HeroNode heroNode2 = new HeroNode(2, "卢俊义", "玉麒麟");HeroNode heroNode3 = new HeroNode(3, "吴用", "智多星");HeroNode heroNode4 = new HeroNode(4, "林冲", "豹子头");//创建一个列表SingleLinkedList singleLinkedList = new SingleLinkedList();//加入singleLinkedList.add(heroNode1);singleLinkedList.add(heroNode2);singleLinkedList.add(heroNode3);singleLinkedList.add(heroNode4);//显示singleLinkedList.list();}
}//定义SingleLinkedList管理节点
class SingleLinkedList {//先初始化一个头节点 头节点不要动 不存放具体的数据private HeroNode head = new HeroNode(0, " ", " ");//添加节点到单向链表//思路,当不考虑编号顺序时//1. 找到当前链表的最后节点//2. 将最后这个节点的next 指向 新的节点public void add(HeroNode heroNode) {//因为head节点不能动 因此需要一个辅助变量tempHeroNode temp = head;//遍历链表 找到最后while (true) {//链表的最后一个节点的next为nullif (temp.next == null) {//说明此时temp就指向了链表的最后temp.next = heroNode;break;} else {temp = temp.next;//将此节点的下一个节点作为新循环的判断(后移一个节点判断)}}}//显示链表[遍历]public void list() {//判断链表是否为空if (head.next == null) {System.out.println("链表为空");return;}//因为head节点不能动 因此需要一个辅助变量temp来遍历HeroNode temp = head.next;while (true) {//输出节点信息System.out.println(temp);//判断是否到链表最后if (temp.next == null) {//说明这个节点是最后一个节点break;}temp = temp.next;//后移一个节点}}
}//定义HeroNode,每个HeroNode对象就是一个节点
class HeroNode {public int no;public String name;public String nickname;public HeroNode next;   //指向下一个节点//构造器public HeroNode(int no, String name, String nickname) {this.no = no;this.name = name;this.nickname = nickname;}@Overridepublic String toString() {return "HeroNode{" +"no=" + no +", name='" + name + '\'' +", nickname='" + nickname + '\'' +", next=" + (next == null ? null : next.hashCode()) +'}';}
}

2.2 按顺序添加节点

实现添加节点时,根据排名将英雄插入到指定位置(如果有这个排名,则添加失败,并给出提示)

在这里插入图片描述

图4 按顺序添加节点示意图

需要按照编号的顺序添加节点 思路:

  1. 首先找到新添加的节点的位置,是通过辅助变量(指针),通过遍历来搞定
  2. 新的节点.next = temp.next
  3. 将 temp.next = 新的节点

自己写代码如下,重写了一下类

//定义SingleLinkedList2按顺序管理节点
class SingleLinkedList2 {//先初始化一个头节点 头节点不要动 不存放具体的数据private HeroNode head = new HeroNode(0, " ", " ");//按顺序添加节点到单向链表public void add(HeroNode heroNode) {if (head.next == null) {//说明此时空链表head.next = heroNode;//直接将此节点添加到头节点的后面return;}HeroNode temp = head;do {if (heroNode.no < temp.next.no) {//将此节点插入到temp和temp.next中间
//                HeroNode temp2 = temp.next;//保存temp的下一个节点
//                temp.next = heroNode;     //将temp下一行节点指向heroNode
//                heroNode.next = temp2;    //将heroNode的下一个节点指向到原temp.nextheroNode.next = temp.next;  //将heroNode的下一个节点指向到temp.nexttemp.next = heroNode;       //将temp下一行节点指向heroNodereturn;  //直接结束战斗} else if (heroNode.no == temp.next.no) {System.out.println("已经当有相同节点了 添加失败 请自重");return;}temp = temp.next; //节点后移} while (temp.next != null);//如果正常退出 说明此对象的序号值最大 直接放在最后面temp.next = heroNode;}//显示链表[遍历]public void list() {if (head.next == null) {System.out.println("别闹宝 空链表~~");return;}HeroNode temp = head;while (temp.next != null) {//如果下一个节点不为空(存了数据)System.out.println(temp.next);  //输出下一个节点temp = temp.next;   //后移到下一个节点}}
}

韩老师教的如下 在SingleLinkedList类中新添加了一个按顺序排列的函数

//第二种方式在添加英雄时 根据排名将英雄插入到指定位置
//(如果有这个排名 则添加失败 并给出提示)
public void addByOrder(HeroNode heroNode) {//因为头节点不能动 因此我们仍然通过一个辅助指针(变量)来帮助找到添加的位置//因为是单链表 找的temp是位于添加位置的前一个节点 否则插入不了HeroNode temp = head;boolean flag = false;   //标志添加的编号是否存在 默认为falsewhile (true) {if (temp.next == null) {//说明temp已经在链表的最后break;}if (temp.next.no > heroNode.no) { //位置找到 就在temp的后面插入break;} else if (temp.next.no == heroNode.no) {  //说明希望添加的heroNode的编号已经存在flag = true;    //说明编号存在break;}temp = temp.next;   //后移一位 相当于遍历链表}//判断flag的值if(flag){   //不能添加 说明编号存在System.out.printf("准备插入的英雄的编号 %d 已经存在了,不能加入\n",heroNode.no);} else {//因为不管是temp.next == null还是temp.next.no > heroNode.no 都需要把heroNode放在temp的后面//加入到链表中 temp的后面heroNode.next = temp.next;temp.next = heroNode;}
}

2.3 单链表节点的修改(根据no编号来修改)

自己写的如下 在类中增加了一个修改函数

//修改节点的信息 根据no编号来修改 即no编号不能改
public void modify(int no, String name,String nickname) {if (head.next == null) {//说明此时空链表System.out.println("空链表 修改失败 改不了");return;}HeroNode temp = head;while (temp.next != null){  //遍历if(no == temp.next.no){ //如果编号相同temp.next.name = name;temp.next.nickname = nickname;return;//结束函数}temp = temp.next;}//如果正常退出循环 则说明没找到对应的编号System.out.println("不好意思,没找到对应编号的位置");
}

韩老师写的如下

//修改节点的信息,根据no编号来修改 即no编号不能改
//说明
//1. 根据newHeroNode 的 no 来修改即可
public void update(HeroNode newHeroNode){//判断是否为空if(head.next == null){System.out.println("链表为空");return;}//找到需要修改的节点 根据no编号//定义一个辅助变量HeroNode temp = head.next;boolean flag = false;//表示是否找到该节点while (true){if(temp == null){break;//已经遍历完链表}if(temp.no == newHeroNode.no){//找到flag = true;break;}temp = temp.next;}//根据flag 判断是否找到要修改的节点if(flag){temp.name = newHeroNode.name;temp.nickname = newHeroNode.nickname;}else {//没有找到System.out.println("修改失败 没有找到");}
}

2.4 单链表节点的删除

自己写的代码如下

//节点的删除 根据no编号来删除
public void delete(int no){if (head.next == null) {//说明此时空链表System.out.println("空链表 删除失败 请自重宝~~");return;}HeroNode temp = head;while (temp.next != null){if(temp.next.no == no){temp.next = temp.next.next; //将temp指向后移两位return;//结束函数}temp = temp.next;//后移一位}//正常退出while 则说明没找到对应的编号System.out.println("没找到对应的编号");
}

韩老师思路如下

  1. 从单链表中删除一个节点的思路
  2. temp.next = temp.next.next
  3. 被删除的节点 将不会有其它引用 会被垃圾回收机制回收

在这里插入图片描述

图5 单链表删除示意图

代码如下

//删除节点
//思路
//1. head 不能动 因此我们需要一个temp辅助找到带删除节点的前一个节点
//2. 说明在比较时 是temp.next.no 和 需要删除的节点的no比较
public void del(int no){HeroNode temp = head;boolean flag = false;   //标志是否找到待删除节点的while (true){if(temp.next == null){  //已经到链表的最后break;}if(temp.next.no == no){//找到待删除节点的前一个节点tempflag = true;break;}temp = temp.next;   //temp后移 遍历}if(flag){//找到//可以删除temp.next = temp.next.next;}else {System.out.println("要删除的节点不存在");}
}

3. 单链表面试题

3.1 求单链表中节点的个数(不统计头节点)

其中就是遍历一遍即可

3.2 查找单链表中的倒数第k个节点

//查找单链表中倒数第k个节点
//思路
//1. 编写一个方法 接收head节点 同时接收一个index
//2. index 表示是倒数第index个节点
//3. 先把链表从头到尾遍历,得到链表的总长度
//4. 得到size后,从链表的第一个开始遍历(size - index)个 就可以得到
//5. 找到则返回该节点 否则返回null
public static HeroNode findLastIndexNode(HeroNode head, int index) {//判断如果链表为空 返回nullif (head.next == null) {return null;    //没有找到}//第一次遍历得到链表的长度int size = getLength(head);//第二次遍历 size - index + 1位置 就是倒数的第k个节点//先做一个index的校验if (index <= 0 || index > size) {return null;}//定义一个辅助变量HeroNode temp = head.next;for (int i = 0; i < size - index; i++) {temp = temp.next;}return temp;
}

3.3 单链表的反转

按照自己写的如下 思路就是每一次分别找到原链表中第size - i 个节点即新链表中第i个节点(包含头节点),然后进行连接

    public static void reverse(HeroNode head) {if (head.next == null) {//判断如果链表为空return;    //没有找到}//第一次遍历得到链表的长度int size = getLength(head);HeroNode temp1 = null;HeroNode temp2 = null;HeroNode temp3 = head.next; //保存好原链表的第一个节点for (int i = 0; i < size; i++) {temp1 = temp3;for (int j = 0; j < size - i - 1; j++) {    //每个大循环依次从原链表中得到最后一个到第一个节点temp1 = temp1.next;}
//            System.out.println(temp1);temp2 = head;for (int j = 0; j < i; j++) {   //每个大循环依次从新链表得到头节点到最后第二个节点temp2 = temp2.next;}
//            System.out.println(i + " " + temp1 + " " + temp2);temp2.next = temp1; //重新将节点连接起来}temp3.next = null;  //切记 别忘了把新链表的最后一个(原链表的第一个)的next置null}

韩老师的思路:

  1. 先定义一个节点 reverseHead = new HeroNode();
  2. 从头到尾遍历原来的链表,每遍历一个节点,就将其取出,并放在新的链表reverseHead的最前端
  3. 原来的链表的head.next=reverseHead.next;
//将单链表反转
public static void reverseList(HeroNode head){//如果当前链表为空 或者只有一个节点 无需反转 直接返回if(head.next == null || head.next.next == null){return;}//定义一个辅助指针(变量) 帮助遍历原来的链表HeroNode cur = head.next;HeroNode next = null;   //指向当前节点[cur]的下一个节点HeroNode reverseHead = new HeroNode(0,"","");//遍历原来的链表 每遍历一个节点 就将其取出 并放在新的链表reverseHead的最前面while (cur != null){next = cur.next;	//保存原链表中的下一个节点 cur.next = reverseHead.next; //先让此节点的next域指向新链表的首位reverseHead.next = cur;     //再将新链表的头部指向此节点 实现cur节点插入cur = next;     //再将该cur引用重新指向原链表没有进行操作的节点}//将head.next 指向reverseHead.next 实现单链表的反转head.next = reverseHead.next;
}

不得不说啊,这韩老师就是牛啊,短短几行代码就搞定了!!!其实就类似于插入,将原链表的节点按顺序插入到新链表的头部与第一个节点之间,此节点就作为新链表的第一个节点。那么最后原链表中的第i个节点就依次排到新链表中的size-i个节点中了。

3.4 从尾到头打印单链表

【方式一:反向遍历 方式二:Stack栈】

3.4.1 逆序输出 反向遍历

韩老师没演示这种 自己写的如下

//遍历逆序输出 
public static void reverseOutput(HeroNode head){if (head.next == null) {//判断如果链表为空return;    //没有找到}//第一次遍历得到链表的长度int size = getLength(head);HeroNode temp1 = null;for (int i = 0; i < size; i++) {temp1 = head.next;for (int j = 0; j < size - i - 1; j++) {    //每个大循环依次从原链表中得到最后一个到第一个节点temp1 = temp1.next;}System.out.println(temp1);}
}
//递归逆序输出
public static void reverseOutputDiGui(HeroNode head){if(head.next==null){//说明到头了}else {reverseOutputDiGui(head.next);}if(head.no != 0){System.out.println(head);}
}
3.4.2 Stack栈

韩老师思路如下

  • 可以利用栈这个数据结构,将各个节点压入到栈中 然后利用栈的先进后出的特点 就实现了逆序打印的效果

    /*** @author 小小低头哥* @version 1.0* 演示Stack的使用*/
    public class TestStack {public static void main(String[] args) {Stack<String> stack = new Stack<>();//入栈stack.add("jack");stack.add("tom");stack.add("smith");//出栈while (stack.size() > 0){System.out.println(stack.pop());//POP就是将栈顶的数据取出}}
    }
    
    //逆序输出
    //利用栈这个数据结构,将各个节点压入到栈中 然后利用栈的先进后出的特点 就实现了逆序打印的效果
    public static void reversePrint(HeroNode head){if (head.next == null) {//判断如果链表为空return;    //空链表 不能打印}//创建一个栈 将各个节点压入栈Stack<HeroNode> stack = new Stack<>();HeroNode cur = head.next;//将链表的所有节点压入栈while (cur != null){stack.push(cur);    //入栈cur = cur.next; //后移}//将战中节点打印while (stack.size() > 0){System.out.println(stack.pop());    //出栈 先进后出}
    }
    

3.5 合并两个有序的单链表,合并之后的链表依然有序

自己苦战出来的,试过输入没毛病的情况下 ,结果还可以

思路:
以链表一为基准,遍历链表一的每一个节点。在遍历每个链表一的节点期间,将链表二中节点编号依次与此时遍历的链表一中 的节点编号进行比较,满足条件的则接在新链表的最后一个节点上。由于是链表一二都是顺序排列,所以一旦链表二中节点编号有不满足条件的,则将此时链表一中遍历的节点接在新链表的最后一个节点上,并跳出遍历链表二的循环,继续遍历链表一中的下一个节点,再接着上次链表二中第一个不满足的节点进行比较(注意不是重新与链表二中的节点一个个比较)。以此循环。

/*** 合并两个有序链表* 但是要确保输入的两个链表都是从小到大排序的 否则需要if(temp2.no <= temp1.no)中的 <= 换成 >=* @param head1* @param head2* @return 合并后的链表*/
public static HeroNode mergeList(HeroNode head1, HeroNode head2) {HeroNode newHero = new HeroNode(0," "," ");//新建一个节点HeroNode end = newHero;   //保存newHero最后一个节点HeroNode temp1 = head1.next; //链表一指针HeroNode temp2 = head2.next; //链表二指针HeroNode next = null;   //保存下一个节点while (true){//以链表一进行顺序遍历while (true){//当链表二中有节点的no 小于链表一中的当前节点的no时if(temp2.no <= temp1.no){ //从小到大排序next = temp2.next;end.next = temp2;//将temp2插入到newHero最后end = end.next; //将end后移一个temp2 = next;   //将temp2指向链表二的下一个节点继续与temp1比较}else {next = temp1.next;end.next = temp1;//将temp1插入到newHero最后end = end.next; //将end后移一个if(next == null){ //说明temp1比较完了 直接把temp2插入到newHero最后end.next = temp2;return newHero;}temp1 = next;   //没比较完 则temp1后移break;  //结束链表二中的节点与链表一中temp1节点的比较(因为是有序的 所以链表二后面的肯定也不符合条件)}if(temp2 == null){//说明链表二中的节点都比较完毕 那么直接把链表一中剩下的节点temp1连接上新链表即可end.next = temp1;return newHero;}}}
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/211483.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

滑动窗口练习(三)— 加油站问题

题目 测试链接 在一条环路上有 n 个加油站&#xff0c;其中第 i 个加油站有汽油 gas[i] 升。 你有一辆油箱容量无限的的汽车&#xff0c;从第 i 个加油站开往第 i1 个加油站需要消耗汽油 cost[i] 升。你从其中的一个加油站出发&#xff0c;开始时油箱为空。 给定两个整数数组…

浮点数在计算机中如何存储

举例&#xff1a; 结果&#xff1a; 文字描述&#xff1a; 先将浮点数转化为二进制的表示形式&#xff0c; 接着将其二进制的形式按照科学计数法来表示&#xff0c; 符号位的确定&#xff1a;正数0&#xff0c; 负数1 指数的确定&#xff1a;将其二进制表示成为科学计数法…

Fall in love with English

Fall in love with English 爱上英语 Hiding behind the loose dusty curtain, a teenager packed up his overcoat into the suitcase. 躲藏在布满尘土的松软的窗帘后边&#xff0c;一个年轻人打包他的外套到行李箱中。 He planned to leave home at dusk though there was th…

超完整的mysql安装配置方法(包含idea和navicat连接mysql,并实现建表)

mysql安装配置方法 1、下载mysql2、解压到指定的安装目录3、配置初始化文件my.ini4、配置用户变量和系统变量5、初始化mysql6、安装mysql服务并启动修改密码7、使用idea连接mysql8、使用Navicat可视化工具连接mysql&#xff0c;并实现新建数据库&#xff0c;新建表 1、下载mysq…

计算机考研408-计算机网络、操作系统整书知识点脑图

计算机网络、操作系统整书知识点脑图 今天突然想起来考研期间为了方便记忆&#xff0c;费了很大力气整理了计算机网络、操作系统两本书知识点的脑图&#xff0c;想着放着也没啥用&#xff0c;分享出来给大家看看 但是思维导图格式的东西好像没法直接发成文章&#xff0c;上传…

免费分享一套Springboot+Vue前后端分离的在线商城系统,挺实用的

大家好&#xff0c;我是java1234_小锋老师&#xff0c;看到一个不错的SpringbootVue前后端分离的在线商城系统&#xff0c;分享下哈。 项目视频演示 【免费】SpringbootVue在线商城系统 毕业设计 Java毕业设计_哔哩哔哩_bilibili【免费】springbootvue在线商城系统 毕业设计 …

97基于matlab的改进的带记忆的模拟退火算法求解TSP问题

基于matlab的改进的带记忆的模拟退火算法求解TSP问题&#xff0c;采用多普勒型降温曲线描述迭代过程&#xff0c;在传统算法的基础上增加记忆功能&#xff0c;可测试中国31/64/144以及att48城市的数据&#xff0c;也可自行输入数据进行测试&#xff0c;测试结果基本达到当前最优…

Swagger2的使用

手写Api文档的几个痛点&#xff1a; 文档需要更新的时候&#xff0c;需要再次发送一份给前端&#xff0c;也就是文档更新交流不及时。 接口返回结果不明确 不能直接在线测试接口&#xff0c;通常需要使用工具&#xff0c;比如postman 接口文档太多&#xff0c;不好管理 Sw…

gin投票项目4

对应视频v2版本 gin项目投票系统4 1.增加一个注册账号的功能 增加接口 参数校验&#xff1a;&#xff08;需求&#xff09; 确认密码需要一致&#xff0c;不为空用户名必须唯一, 不为空用户名大于8小于16位密码大于8小于16位,并且不能为纯数字 正则表达式 必须知道这东西…

我对迁移学习的一点理解(系列2)

文章目录 我对迁移学习的一点理解 我对迁移学习的一点理解 源域和目标域是相对的概念&#xff0c;指的是在迁移学习任务中涉及到的两个不同的数据集或领域。 源域&#xff08;Source Domain&#xff09;通常指的是已经进行过训练和学习的数据集&#xff0c;它被用来提取特征、…

Nginx缓存及HTTPS配置小记

缓存基础 缓存分类 某些场景下&#xff0c;Nginx需要通过worker到上有服务中获取数据并将结果响应给客户端&#xff0c;在高并发场景下&#xff0c;我们完全可以将这些数据视为热点数据&#xff0c;并将其缓存到Nginx服务上。 客户端缓存&#xff1a;将缓存数据放到客户端。 …

yolov8与yolov5网络对比

回顾一下YOLOv5&#xff0c;不然没机会了 这里粗略回顾一下&#xff0c;这里直接提供YOLOv5的整理的结构图吧&#xff1a; Backbone&#xff1a;CSPDarkNet结构&#xff0c;主要结构思想的体现在C3模块&#xff0c;这里也是梯度分流的主要思想所在的地方&#xff1b;PAN-FPN&…

OFDM模糊函数仿真

文章目录 前言一、OFDM 信号及模糊函数1、OFDM 信号表达式2、模糊函数表达式 二、MATLAB 仿真1、MATLAB 核心源码2、仿真结果①、OFDM 模糊函数②、OFDM 距离模糊函数③、OFDM 速度模糊函数 前言 本文进行 OFDM 的仿真&#xff0c;首先看一下 OFDM 的模糊函数仿真效果&#xf…

【vim】常用操作

用的时候看看&#xff0c;记太多也没用&#xff0c;下面都是最常用的&#xff0c;更多去查文档vim指令集。 以下均为正常模式下面操作&#xff0c;正在编辑的&#xff0c;先etc一下. 1/拷贝当前行 yy&#xff0c;5yy为拷贝包含当前行往下五行 2/p将拷贝的东西粘贴到当前行下…

Java、JDK、JRE、JVM

Java、JDK、JRE、JVM 一、 Java 广义上看&#xff0c;Kotlin、JRuby等运行于Java虚拟机上的编程语言以及相关的程序都属于Java体系的一员。从传统意义上看&#xff0c;Java社区规定的Java技术体系包括以下几个部分&#xff1a; Java程序设计语言各种硬件平台上的Java虚拟机实…

【力扣】移除链表元素203

目录 1.前言2. 题目描述3. 题目分析3.1 不带哨兵位3.2 带哨兵位 4. 附代码4.1 不带哨兵位4.2 带哨兵位 1.前言 这里开始介绍从网上一些刷题网站上的题目&#xff0c;在这里做一些分享&#xff0c;和学习记录。 先来介绍一些力扣的OJ题目。 这里的OJ就是我们不需要写主函数&…

数据表记录的操作

一、数据添加 1、打开SSMS&#xff0c;附加数据库&#xff08;数据库文件在自己的文件夹下面&#xff09;&#xff0c;并进行下面的设置&#xff1a; &#xff08;1&#xff09;设置“部门信息”表中的“编号”为主键&#xff08;SSMS&#xff09; 首先建立好所需的数据库库…

华为OD机试 - 生成哈夫曼树(Java JS Python C)

题目描述 给定长度为 n 的无序的数字数组,每个数字代表二叉树的叶子节点的权值,数字数组的值均大于等于1。 请完成一个函数,根据输入的数字数组,生成哈夫曼树,并将哈夫曼树按照中序遍历输出。 为了保证输出的二叉树中序遍历结果统一,增加以下限制: 二叉树节点中,左节…

为 Compose MultiPlatform 添加 C/C++ 支持(3):实战 Desktop、Android、iOS 调用同一个 C/C++ 代码

theme: serene-rose 前言 在本系列的前两篇文章中我们已经学会了如何在 kotlin native 平台&#xff08;iOS&#xff09;使用 cinterop 调用 C/C 代码。以及在 jvm 平台&#xff08;Android、Desktop&#xff09;使用 jni 调用 C/C 代码&#xff0c;并且知道了如何自动编译 A…

Git 五分钟教程速度入门

Git 五分钟教程速度入门 分类 编程技术 许多人认为 Git 太混乱&#xff0c;或认为它是一种复杂的版本控制系统&#xff0c;其实不然&#xff0c;这篇文章有助于大家快速上手使用 Git。 入门 使用Git前&#xff0c;需要先建立一个仓库(repository)。您可以使用一个已经存在的…