链表——Java实现
来源:互联网 发布:淘宝集市店 编辑:程序博客网 时间:2024/05/16 19:28
链表的基本结构
public class LNode { public String data;//节点数据 LNode next;//下一个节点}
这是最基本的链表结构,还有双向链表和循环链表会在文章最后提到。
建立单链表
头部插入建立单链表
头部插入建立方式的思想是,首先建立一个指针,
1.然后新建第一个节点,让指针指向这个节点
2.然后再新建一个节点,通过指针拿到第一个点的地址,让新建的下一个地址指向第一个节点。
3.最后把指针移动到第一个节点上。
后面重复这个过程就可以
大家可以根据这张图来理解一下。
下面是实现的代码
// 在头部插入 public LNode Creat_LinkListHead() { LNode head = null;// 头部,空表 System.out.println("现在使用头部插入法,请输入数据,以0为结束"); String newDate; while (!(newDate = in.next()).equals("0")) { LNode newNode = new LNode();//新建一个节点 newNode.data = newDate; newNode.next = head;//通过指针找到上一个节点地址,让新节点的下一个地址指向新节点 head = newNode;//让指针移动到新建的节点上 } System.out.println("录入完毕"); return head; }
在尾部插入建立链表
在头部插入的方式,有一个很大的问题,就是最后我指针的位置,在整个链表逻辑上
的最后位,遍历的时候,会反过来,比方说建立的顺序是ABCDE,遍历的时候就是EDCBA了
在尾部插入建立的方式就是为解决这个问题
尾部插入的思路是:首先我们建立一个头节点和一个尾节点,让头节点和尾节点一起指向第一个节点,之后的话头结点不再变动,尾节点用头部插入的方式建立起链表,可以发现这个方式和头部插入没有什么区别,主要就是增加了一个头节点。
下面是实现的代码
// 在尾部插入 public LNode Creat_LinkListTail() { LNode H = null;// 头指针 LNode R = null;// 尾指针 String newDate; System.out.println("现在使用尾部插入法,以0为结束"); while (!(newDate = in.next()).equals("0")) { LNode newNode = new LNode(); newNode.data = newDate; // 第一个指针 if (H == null) { H = newNode; } else { R.next = newNode; } //指针移动到创建的新节点 R = newNode; } //让随后一个节点指向null if (R != null) R.next = null; return H; }
带头节点的尾部插入
上面方式也有一个问题,第一个节点由于没有前驱,所以我们在很多操作的时候都要考虑这个特殊的点,这样在增加删除的时候都会比较麻烦,比较好的解决方式,我们可以第一个节点前面在加一个节点,这个节点没有数据,只是指向原来的第一个节点。如下图
H代表的是头指针
R代表的是尾指针
新增一个头结点后就可以很好的解决这个问题,但在遍历,定位节点的时候要注意哥不带头结点的链表的区别,这个头结点 只是用来作为前驱存放原本第一个节点的地址的。
public LNode Creat_LinkListTailWithHead() { LNode H = null;//头指针 LNode R = null;//尾指针 //建立头结点 LNode headNode = new LNode(); headNode.next = null; H = headNode; R = headNode; System.out.println("现在使用带头结点的的链表尾部插入,输入0为结束"); String newDate; while(!(newDate=in.next()).equals("0")){ LNode newNode = new LNode(); newNode.data = newDate; newNode.next = null; R.next = newNode; R=newNode; } R.next = null; return H; }
遍历链表
遍历的思路是从头结点开始,输出节点的数据, 之后让指针移动到下一个节点
//遍历链表 public void look(LNode head) { if (head == null) { System.out.println("链表为空"); System.exit(0); } LNode flag = head;//用一个指针来拿到头结点的地址 do { System.out.print(flag.data); flag = flag.next;//下移到下一个节点 } while (flag != null);//如果节点为空结束循环 }
当然这个遍历是有问题的,没有判断链表有没有带头结点,大家可以自行修改一下。
计算链表长度
这个的思路的遍历差不多,只不过我们需要定义一个变量用来存储长度
//计算带头结点的链表的长度 public int lenth_haveHead(LNode H){ int len = 0 ;//用来存放长度 while(H.next!=null){ H=H.next; len++; } return len; } //不带头结点的链表的长度 public int lenth_nothaveHead(LNode H){ int len = 0;//用来存放长度 //判断链表是否为空 if(H==null){ System.out.println("链表为空"); return 0; } len = 1; while(H.next!=null){ H = H.next; len++; } return len; }
可以看出,带头节点的链表在遍历上就比不带的方便很多。
查询指定节点
//查询指定节点 //n 代表第几个节点 public LNode findLNode(int n,LNode H){ LNode myH; if(H.data == null){ //带头结点 myH = H.next; }else{ //不带头结点 myH = H; } int len = 0; while(myH!=null){ len++; if(len == n) break; myH = myH.next; } return myH; }
首先我们知道带头节点的链表的第一个节点,没有数据,用这个作为标志来判断链表是哪种链表。
如果是带头结点的,那链表的第一位应该是头结点.next
后排插入
后排插入就是在一个节点的后面,插入一个新节点
思路如下
我们先找到这个节点
通过这个节点的next得到下一个节点的地址,让新节点的next指向下一个节点。
让被插的节点将next指向新的节点
下面给出实现代码
//在第n的节点后插入data public void insertBehind(String data,int n,LNode H){ MyLinkList list = new MyLinkList(); LNode newNode = new LNode();//新建节点 newNode.data = data; newNode.next = null; LNode node = list.findLNode(n, H);//找到要插入的位置 if(node == null) { System.out.println("找不到节点"); return; } //获取前驱的next,也就是下一个节点 newNode.next = node.next; //让前驱指向新的节点 node.next = newNode; }
前排插入
前排插入的思想和后排插入差不多,只不过我们再拿到节点后,需要再去查找一次,找到这的节点的前驱,之后以这个前驱做后排插入就行了。
/* * 在第n个节点前面插入一个节点 * */ public void insertFront(String data,int n,LNode H){ LNode newNode = new LNode(); newNode.data = data; newNode.next = null; MyLinkList list = new MyLinkList(); //找到要插入的节点 LNode node = list.findLNode(n, H); if(node==null){ System.out.println("找不到节点"); return; } //找到node节点的前驱 LNode myH = H; while(myH.next!=node){ myH = myH.next; } newNode.next = node; myH.next = newNode; }
删除节点
删除节点的思路如下:
找到要删除的节点
再找到他的前驱节点
让前驱的next指向这个节点的next,这个时候要删除的节点已经被架空了
最后我们给这个要删除的节点赋值null 释放空间
MyLinkList list = new MyLinkList(); LNode node = list.findLNode(n, H); if(node == null) { System.out.println("找不到要删除的节点"); return; } //找到这个节点的前驱 LNode frontNode = list.findLNode(n-1, H); if(frontNode==null){ System.out.println("找不到前驱"); return; } frontNode.next = node.next; node = null; }
循环链表
循环链表就是将最后一个节点,原来指向空,改成指向头部,实质上并没有什么区别,主要是判断是不能用null来做链表结束的条件了
双向链表
单向的连接再很多时候会有麻烦,比如我们的前排插入,我们要得到前驱,不得不再做一次遍历,双向链表正是为了解决这个问题,我们再结构中再加一个指针让他指向前驱就可以了。
- 链表——Java实现
- 实现二分法查找——java实现
- 栈——java实现
- 队列——java实现
- JAVA——实现多线程
- Dijkstra——Java实现
- 红黑树——java实现
- JAVA实现——单链表
- 队列——Java实现
- Java实现——求丑数
- java实现—身份证号码验证
- 百钱买百鸡—java程序实现
- java实现—身份证号码验证
- 希尔排序—java实现
- 冒泡排序—java实现
- 插入排序—java实现
- 选择排序—java实现
- 快速排序—java实现
- Oracle in exists
- 58 同城 iOS 客户端 Hybrid 框架探索
- java 实现http响应
- 视频学习笔记:Android ffmpeg解码多路h264视频并显示
- 基于注解的Spring整合SpringMVC开发流程?
- 链表——Java实现
- java-访问修饰符
- ngixn如何控制多进程连接的平衡
- 图解集合3:CopyOnWriteArrayList
- hibernate中merge的使用以及与update的区别
- ACM一些常用小技巧(博客收集+总结)
- hibernate一对一外键映射
- Oracle数据库的基本操作指令
- 前端页码栏的制作