java 单链表是什么算法_数据结构与算法-java-单链表

首先搞懂什么是链表

链表是一种物理存储单元上非连续、非顺序的存储结构,数据元素的逻辑顺序是通过链表中的指针链接次序实现的,链表通过一个指向下一个元素地址的引用将链表中的元素串起来。

那么再对比一下数组

数组的内存是连续分配的,并且是静态分配的,即在使用数组之前需要分配固定大小的空间。可以通过索引直接得到数组中的而元素,即获取数组中元素的时间复杂度为O(1)。

链表分类

链表分为单向链表(Singly linked lis)、双向链表(Doubly linked list)、循环链表(Circular Linked list)。

它在内存里面的实际结构如下,而我们大多探究的是链表的逻辑结构

逻辑和实际的区别就是他的next有可能在180而它本身在110这个地址如下所示。而为了方便我们依然把它们挨着画出并连接

bd87a99ec4f97492043bb1a02177643e.png

单向链表(Singly linked lis)

单向链表是最简单的链表形式。我们将链表中最基本的数据称为节点(node),每一个节点包含了数据块和指向下一个节点的指针

逻辑结构如下(带头结点)

2e41aa7150ebe6de78cff3c62567deac.png

那么我们用一个实例看看单链表

83141fa791f85381f79d83ed500a1c27.png

e8126922dcc64a9dd29eacfaa88fdfda.png

下面来看代码

public classSingleLinkedListDemo {public static voidmain(String[] args) {//测试//先创建节点

HeroNode hero1 = new HeroNode(1, "宋江", "及时雨");

HeroNode hero2= new HeroNode(2, "卢俊义", "玉麒麟");

HeroNode hero3= new HeroNode(3, "吴用", "智多星");

HeroNode hero4= new HeroNode(4, "林冲", "豹子头");//创建要给的链表

SingleLinkedList singleLinkedList = newSingleLinkedList();//加入

singleLinkedList.add(hero1);

singleLinkedList.add(hero2);

singleLinkedList.add(hero3);

singleLinkedList.add(hero4);//显示

singleLinkedList.show();

}

}classSingleLinkedList{//先初始化的头结点,不存放数据

private HeroNode head = new HeroNode(0,"","");//add//添加的第一步是找到这个链表的最后那个节点,将最后节点的next指向新的即可

public voidadd(HeroNode heroNode)

{//因为head头结点不能动,所以需要辅助temp

HeroNode temp = head;//复制过去,既不破坏head又能遍历//遍历链表,找到最后

while (true) {//找到链表最后

if (temp.next == null) {break;

}//如果没有找到最后就后移

temp=temp.next;//继续循环while到if去直到找到最后,跳出循环即break所以出来时候的temp一定是最后节点

}//将最后节点的next指向add的

temp.next =heroNode ;

}//show

public voidshow(){//判断是否链表空

if(head.next == null) {

System.out.println("链表为空");return;

}else{

HeroNode temp=head.next;while (true)

{//到最后了,老规矩

if(temp.next ==null)

{break;

}//没到最后就输出

System.out.println(temp); //因为我们呢重写了tostring方法,直接就可以打印chu//后移,不然一直原地踏步

temp =temp.next;

}

}

}

}//先定义一个HeroNode,每一个HeroNode就是一个节点,就是代替c++中的struct

classHeroNode{public intno;publicString name;publicString nickname;public HeroNode next; //指向下一节点//构造器

public HeroNode(intno, String name, String nickname) {this.no =no;this.name =name;this.nickname =nickname;

}//为了显示方便

@OverridepublicString toString() {return "HeroNode{" +

"no=" + no +

", name='" + name + '\'' +

", nickname='" + nickname + '\'' +

", next=" + next +

'}';

}

}

但是结果还差了一点,很是奇怪。如下

HeroNode{no=1, name='宋江', nickname='及时雨', next=HeroNode{no=2, name='卢俊义', nickname='玉麒麟', next=HeroNode{no=3, name='吴用', nickname='智多星', next=HeroNode{no=4, name='林冲', nickname='豹子头', next=null}}}}

HeroNode{no=2, name='卢俊义', nickname='玉麒麟', next=HeroNode{no=3, name='吴用', nickname='智多星', next=HeroNode{no=4, name='林冲', nickname='豹子头', next=null}}}

HeroNode{no=3, name='吴用', nickname='智多星', next=HeroNode{no=4, name='林冲', nickname='豹子头', next=null}}

发现是我们的next={}出了问题,因为把所有后面的next一起打印出来了 。因为Next也可以说就是指后面的

所以改为如下

@Override

public String toString() {

return "HeroNode{" +

"no=" + no +

", name='" + name + '\'' +

", nickname='" + nickname + '\'' +

'}';

}

再运行即可

236a3a3827371c35e0c382847892072d.png

上面的是顺序插入,那么我们不顺插而是在中间插入

中间插入就是

66b3182f2ab6a5ff125c16ba2026d6cf.png

1e50a16e39dbd2804dfbdc18b3693e0d.png

中间插入的好处就是他的顺序即no永远都是从小到大的

代码如下

//中间插

public voidaddByOrder(HeroNode heroNode)

{//因为节点不能动,任然设置辅助temp//我们现在要找的就不是最后节点,而是要插入的前一个节点

HeroNode temp =head;//标识添加的英雄是否已经存在

boolean flag = false;while (true) {//说明temp到了链表最后

if (temp.next == null) {break;

}if(temp.next.no>heroNode.no)

{//位置找到了就在temp的后面

break;

}else if(temp.next.no==heroNode.no)

{//说明编号存在

flag=true;break;

}

temp= temp.next;//后移,遍历链表

}if(flag=true)

{//说明编号存在

System.out.printf("英雄的编号%d已经存在",heroNode.no);

}else{//没有存在,插入进入

heroNode.next=temp.next;

temp.next=heroNode;

}

知道这些以后那么修改也变得简单

//修改,no不变

public voidupdate(HeroNode heroNode) {//判断是否为空

if (head.next == null) {

System.out.println("链表为空");return;

}

HeroNode temp=head.next;boolean flag = false; //标识是否找到该节点

while (true) {//最后了必须退出,即遍历完也没找到

if (temp.next == null) {break;

}if (temp.no ==heroNode.no) {//找到了

flag = true;break;

}

temp=temp.next;

}if(flag=true)

{

temp.name=heroNode.name;

temp.nickname=heroNode.nickname;

}else{

System.out.printf("没有找到编号%d的节点",heroNode.no);

}

}

那么接下来我们再看一看其他的方法等

ee47c956fd4651a81b3e769b383e62e1.png

有了上面这个getLength后再看看一个结合的案例

27def54ff6392690a1e78857d7f5c689.png

671171d12a6d0c44762b887e53d612b0.png

那么我们现在再看一个案例

5e078070f8bc1552ff07e6fc64d30397.png

852635946adf36feb6ab05ff42449036.png

a601264eb9bf96a330ca0d975008b8dc.png

大概思路就是

1重新再来一个链表

2然后遍历原来的链表并取出中间插入新链表的前面位置及head->next,这样就实现了反序

3原来链表的头部信息复制到新链表即可

c2705948b5f381f103650e1cef7b86ac.png

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
单链表是一种常见的数据结构,它由一个或多个节点组成,每个节点包含一个数据域和一个指针域,指针域指向下一个节点。 实现单链表的查找位序算法函数需要以下步骤: 1. 定义一个指针p指向链表的头节点,并定义一个变量count,用于计数。 2. 从头节点开始,遍历链表,当p指向某个节点时,计数器count加1。 3. 如果p指向的节点的数据与目标数据相等,则返回当前的计数器count,即为目标数据的位序。 4. 如果p指向的节点不是目标数据,则将p指向下一个节点,重复步骤3。 5. 如果遍历完链表后仍未找到目标数据,则返回-1,表示未找到。 下面是C语言实现单链表查找位序算法函数的代码示例: ```c #include <stdio.h> #include <stdlib.h> // 定义单链表节点结构 typedef struct Node { int data; // 数据域 struct Node* next; // 指针域 } Node; // 查找位序的算法函数 int findPosition(Node* head, int target) { Node* p = head; // 指向头节点 int count = 0; // 计数器初始化为0 while (p != NULL) { count++; // 计数器加1 if (p->data == target) { return count; // 找到目标数据,返回当前计数器的值 } p = p->next; // 指向下一个节点 } return -1; // 遍历完链表未找到目标数据,返回-1 } int main() { // 创建链表 Node* head = (Node*)malloc(sizeof(Node)); head->data = 1; // 头节点数据为1 Node* node1 = (Node*)malloc(sizeof(Node)); node1->data = 2; Node* node2 = (Node*)malloc(sizeof(Node)); node2->data = 3; head->next = node1; node1->next = node2; node2->next = NULL; // 查找位序示例 int target = 3; // 目标数据为3 int position = findPosition(head, target); if (position != -1) { printf("目标数据 %d 的位序为 %d\n", target, position); } else { printf("未找到目标数据 %d\n", target); } // 释放链表内存 free(node2); free(node1); free(head); return 0; } ``` 在上述代码中,我们首先定义了一个指向头节点的指针p和一个计数器count,然后使用while循环遍历链表。当p指向某个节点时,计数器加1,并判断该节点的数据是否与目标数据相等。如果找到了目标数据,则返回当前计数器的值,即为目标数据的位序。如果遍历完链表仍未找到目标数据,则返回-1表示未找到。最后在主函数中演示了调用该算法函数的示例。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值