Java实现链表的常见操作算法
链表分为单链表,双向链表和循环链表,是一种链式存储结构,由一个个结点链式构成,结点包含数据域和指针域,其中单链表是只有一个指向后驱结点的指针,双向链表除头结点和尾结点外,每个结点都有一个前驱指针和一个后继指针,循环链表的尾结点的指针指向头结点.
相比数组而言,链表的插入和删除比较快,查询慢.
本文主要以单链表为例,介绍下链表的常用算法操作.
单链表的结构:
在java语言中,链表的每个结点用Node类来表示:
package com.linkedlist; public class Node {
private int data;// 结点数据
private Node next;// 下一个结点 public Node(int data) {
this.data = data;
} public int getData() {
return data;
} public void setData(int data) {
this.data = data;
} public Node getNext() {
return next;
} public void setNext(Node next) {
this.next = next;
}
}
定义一个链表操作类,里面包含常用的操作:
package com.linkedlist; import java.util.Hashtable; public class LinkedListOperator {
private Node head = null;// 头结点 // 在链表的末尾增加一个结点
private void addNode(int data) {
Node newNode = new Node(data);
if (head == null) {
head = newNode;
return;
}
Node temp = head;
while (temp.getNext() != null) {
temp = temp.getNext();
}
temp.setNext(newNode);
} // 打印链表结点
private void printLink() {
Node curNode = head;
while (curNode != null) {
System.out.println(curNode.getData());
curNode = curNode.getNext();
}
System.out.println("===========");
} // 求链表长度
private int getLength() {
int len = 0;
Node curNode = head;
while (curNode != null) {
len++;
curNode = curNode.getNext();
}
return len;
} // 删除某一个结点
private boolean delNode(int index) {
if (index < 1) {
return false;
}
if (index == 1) {
head = head.getNext();
return true;
}
Node preNode = head;
Node curNode = head.getNext();
int n = 1;
while (curNode.getNext() != null) {
if (n == index) {
preNode.setData(curNode.getData());
preNode.setNext(curNode.getNext());
return true;
}
preNode = preNode.getNext();
curNode = curNode.getNext();
n++;
}
if (curNode.getNext() == null) {
preNode.setNext(null);
}
return false;
} // 链表排序:选择排序法,从小到大
private void sortList() {
Node curNode = head;
while (curNode != null) {
Node nextNode = curNode.getNext();
while (nextNode != null) {
if (curNode.getData() > nextNode.getData()) {
int temp = curNode.getData();
curNode.setData(nextNode.getData());
nextNode.setData(temp);
}
nextNode = nextNode.getNext();
}
curNode = curNode.getNext();
}
} // 去掉重复元素
private void distinctLink() {
Hashtable<Integer, Integer> map = new Hashtable<Integer, Integer>();
Node curNode = head;
Node preNode = null;
while (curNode != null) {
if (map.containsKey(curNode.getData())) {
preNode.setData(curNode.getData());
preNode.setNext(curNode.getNext());
} else {
map.put(curNode.getData(), 1);
preNode = curNode;
}
curNode = curNode.getNext();
}
} // 返回倒数第k个结点,定义两个指针,第一个指针向前移动K-1次,之后两个指针同时前进,
// 当第一个指针到达末尾时,第二个指针所在的位置即为倒数第k个结点
private Node getReverNode(int k) {
if (k < 1) {
return null;
}
Node first = head;
Node second = head;
for (int i = 0; i < k - 1; i++) {
first = first.getNext();
}
while (first.getNext() != null) {
first = first.getNext();
second = second.getNext();
}
return second;
} // 反转链表
private void reserveLink() {
Node preNode = null;
Node curNode = head;
Node tempNode = null;
while (curNode != null) {
tempNode = curNode.getNext();
curNode.setNext(preNode);
preNode = curNode;
curNode = tempNode;
}
head = preNode;
} // 寻找链表的中间结点
private Node getMiddleNode() {
Node slowNode = head;
Node quickNode = head;
while (slowNode.getNext() != null && quickNode.getNext() != null) {
slowNode = slowNode.getNext();
quickNode = quickNode.getNext().getNext();
}
return slowNode;
} // 判断链表是否有环
private boolean isRinged() {
if (head == null) {
return false;
}
Node slowNode = head;
Node quickNode = head;
while (slowNode.getNext() != null && quickNode.getNext() != null) {
slowNode = slowNode.getNext();
quickNode = quickNode.getNext().getNext();
if (slowNode.getData() == quickNode.getData()) {
return true;
}
}
return false;
} // 删除指定结点
private boolean delNode(Node node) {
if (node.getNext() == null) {
return false;// 在不知道头结点的情况下,没法删除单链表的尾结点
}
node.setData(node.getNext().getData());
node.setNext(node.getNext().getNext());
return true; } // 判断两个链表是否相交:相交的链表的尾结点相同
private boolean isCross(Node n1, Node n2) {
while (n1.getNext() != null) {
n1 = n1.getNext();
}
while (n2.getNext() != null) {
n2 = n2.getNext();
}
if (n1.getData() == n2.getData()) {
return true;
}
return false;
} // 求相交链表的起始点
private Node getFirstCrossNode(LinkedListOperator l1, LinkedListOperator l2) {
int len = l1.getLength() - l2.getLength();
Node n1 = l1.head;
Node n2 = l2.head;
if (len > 0) {
for (int i = 0; i < len; i++) {
n1 = n1.getNext();
}
} else {
for (int i = 0; i < len; i++) {
n2 = n2.getNext();
}
}
while (n1.getData() != n2.getData()) {
n1 = n1.getNext();
n2 = n2.getNext();
}
return n1;
} public static void main(String[] args) {
LinkedListOperator llo = new LinkedListOperator();
llo.addNode(10);
llo.addNode(4);
llo.addNode(6);
llo.addNode(8);
llo.printLink();
// llo.delNode(4);
// llo.sortList();
// llo.distinctLink();
// System.out.println(llo.getReverNode(3).getData());
// llo.reserveLink();
// System.out.println(llo.getMiddleNode().getData());
// System.out.println(llo.isRinged());
llo.delNode(llo.head.getNext().getNext());
llo.printLink();
}
}
未完待续...
Java实现链表的常见操作算法的更多相关文章
- Java实现7种常见密码算法
原创:扣钉日记(微信公众号ID:codelogs),欢迎分享,转载请保留出处. 简介 前面在密码学入门一文中讲解了各种常见的密码学概念.算法与运用场景,但没有介绍过代码,因此,为作补充,这一篇将会介绍 ...
- Java中几种常见排序算法
日常操作中常见的排序方法有:冒泡排序.快速排序.选择排序.插入排序.希尔排序等. 冒泡排序是一种简单的排序算法.它重复地走访过要排序的数列,一次比较两个元素,如果他们的顺序错误就把他们交换过来.走访数 ...
- Java的几种常见排序算法
一.所谓排序,就是使一串记录,按照其中的某个或某些关键字的大小,递增或递减的排列起来的操作.排序算法,就是如何使得记录按照要求排列的方法.排序算法在很多领域得到相当地重视,尤其是在大量数据的处理方面. ...
- 【知了堂学习笔记】java 编写几种常见排序算法3
排序的分类: 1.希尔排序 希尔排序是快速插入排序的改进版,希尔排序是把记录按下标的一定增量分组,对每组使用直接插入排序算法排序:随着增量逐渐减少,每组包含的关键词越来越多,当增量减至1时,整个文件恰 ...
- 【知了堂学习笔记】java 编写几种常见排序算法
排序的分类: 一.交换排序 所谓交换,就是根据序列中两个记录键值的比较结果来对换这两个记录在序列中的位置,交换排序的特点是:将键值较大的记录向序列的尾部移动,键值较小的记录向序列的前部移动. 1.冒泡 ...
- 【知了堂学习笔记】java 编写几种常见排序算法2
排序的分类: 1.直接选择排序 它的基本思想是:第一次从R[0]~R[n-1]中选取最小值,与R[0]交换,第二次从R[1]~R[n-1]中选取最小值,与R[1]交换,....,第i次从R[i-1]~ ...
- 【java】String类常见操作
秋招做题需要,总结String类常用api如下: 简单的:str.length().str.isEmpty().str.split(“;”)切割 1.字符串反转:借助StringBuilder/Str ...
- 读Hadoop3.2源码,深入了解java调用HDFS的常用操作和HDFS原理
本文将通过一个演示工程来快速上手java调用HDFS的常见操作.接下来以创建文件为例,通过阅读HDFS的源码,一步步展开HDFS相关原理.理论知识的说明. 说明:本文档基于最新版本Hadoop3.2. ...
- java实现单链表常见操作
一.概述: 本文主要总结单链表常见操作的实现,包括链表结点添加.删除:链表正向遍历和反向遍历.链表排序.判断链表是否有环.是否相交.获取某一结点等. 二.概念: 链表: 一种重要的数据结构,HashM ...
随机推荐
- 开发模型之V模型
1.模型目的: V模型的目的在于改进软件开发的效率和效果. 2.常见理论性描述: V模型从整体上看起来,就是一个V字型的结构,由左右两边组成. 左边的下划线分别代表了需求分析.概要设计.详细设计.编 ...
- MVC开发T4代码生成之二----vs模板扩展
在上一篇MVC开发T4代码生成之一----文本模板基础中介绍了与T4模板相关的基础知识,并对MVC内使用T4模板添加视图做了介绍.知道了T4模板的使用后自然就想着怎么对vs自带的T4模板进行扩展,添加 ...
- Win10系统,开机后提示Desktp不可用的故障解决方法。
WIN10桌面位置不可用的故障解决方法 今天电脑开机 (Win10系统).桌面空了,然后就蒙了. 系统并弹出以下框,如下图: 原因可能是因为昨天晚上熬夜测试脚本.网上下载的脚本大多都是有毒的.但是人懒 ...
- 31. pt-variable-advisor
pt-variable-advisor h=192.168.100.101,P=3306,u=admin,p=admin mysqladmin var>/root/test/pt-variabl ...
- HDU 6041.I Curse Myself 无向仙人掌图
I Curse Myself Time Limit: 8000/4000 MS (Java/Others) Memory Limit: 131072/131072 K (Java/Others) ...
- 《Miracle-House团队》项目需求分析改进
(一)团队项目需求分析改进 一.<西小餐项目需求规格说明书>的不足 通过老师和其他同学的指正和建议,我们发现上次的需求规格说明书存在以下不足: 1.需求规格文档不够完整和规范: 2.系统设 ...
- Vue的双向数据绑定
最简单的实现v-model数据绑定,只需要在一个组件里面有个props,加上一个value,然后当组件要去修改数据的时候, $emit一个input事件,并且把新的值传出去.这就实现了Vue里面的数据 ...
- 对于新版本的webstorm对vue的支持
webstorm 对于官方vue的支持,直到2017.1,这个版本,之后的版本不能直接安装vue插件,这时候就需要自己手动新建vue模板了
- Jmeter 聚合报告---测试结果分析
当我们测试完后,最关心就是结果数据了,下面一起来分析Jmeter聚合报告数据. 首先来看下Jmeter的help是如何解释这些含义的. 1.Label - The label of the sampl ...
- 85、int 、NSInteger、NSUInteger、NSNumber的区别和联系
NSNumber是NSValue的一个子类,它是一个对象来存储数字值包括bool型,它提供了一系列的方法来存储char a signed or unsigned char, short int, in ...