链表分为单链表,双向链表和循环链表,是一种链式存储结构,由一个个结点链式构成,结点包含数据域和指针域,其中单链表是只有一个指向后驱结点的指针,双向链表除头结点和尾结点外,每个结点都有一个前驱指针和一个后继指针,循环链表的尾结点的指针指向头结点.

相比数组而言,链表的插入和删除比较快,查询慢.

本文主要以单链表为例,介绍下链表的常用算法操作.

单链表的结构:

在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实现链表的常见操作算法的更多相关文章

  1. Java实现7种常见密码算法

    原创:扣钉日记(微信公众号ID:codelogs),欢迎分享,转载请保留出处. 简介 前面在密码学入门一文中讲解了各种常见的密码学概念.算法与运用场景,但没有介绍过代码,因此,为作补充,这一篇将会介绍 ...

  2. Java中几种常见排序算法

    日常操作中常见的排序方法有:冒泡排序.快速排序.选择排序.插入排序.希尔排序等. 冒泡排序是一种简单的排序算法.它重复地走访过要排序的数列,一次比较两个元素,如果他们的顺序错误就把他们交换过来.走访数 ...

  3. Java的几种常见排序算法

    一.所谓排序,就是使一串记录,按照其中的某个或某些关键字的大小,递增或递减的排列起来的操作.排序算法,就是如何使得记录按照要求排列的方法.排序算法在很多领域得到相当地重视,尤其是在大量数据的处理方面. ...

  4. 【知了堂学习笔记】java 编写几种常见排序算法3

    排序的分类: 1.希尔排序 希尔排序是快速插入排序的改进版,希尔排序是把记录按下标的一定增量分组,对每组使用直接插入排序算法排序:随着增量逐渐减少,每组包含的关键词越来越多,当增量减至1时,整个文件恰 ...

  5. 【知了堂学习笔记】java 编写几种常见排序算法

    排序的分类: 一.交换排序 所谓交换,就是根据序列中两个记录键值的比较结果来对换这两个记录在序列中的位置,交换排序的特点是:将键值较大的记录向序列的尾部移动,键值较小的记录向序列的前部移动. 1.冒泡 ...

  6. 【知了堂学习笔记】java 编写几种常见排序算法2

    排序的分类: 1.直接选择排序 它的基本思想是:第一次从R[0]~R[n-1]中选取最小值,与R[0]交换,第二次从R[1]~R[n-1]中选取最小值,与R[1]交换,....,第i次从R[i-1]~ ...

  7. 【java】String类常见操作

    秋招做题需要,总结String类常用api如下: 简单的:str.length().str.isEmpty().str.split(“;”)切割 1.字符串反转:借助StringBuilder/Str ...

  8. 读Hadoop3.2源码,深入了解java调用HDFS的常用操作和HDFS原理

    本文将通过一个演示工程来快速上手java调用HDFS的常见操作.接下来以创建文件为例,通过阅读HDFS的源码,一步步展开HDFS相关原理.理论知识的说明. 说明:本文档基于最新版本Hadoop3.2. ...

  9. java实现单链表常见操作

    一.概述: 本文主要总结单链表常见操作的实现,包括链表结点添加.删除:链表正向遍历和反向遍历.链表排序.判断链表是否有环.是否相交.获取某一结点等. 二.概念: 链表: 一种重要的数据结构,HashM ...

随机推荐

  1. blender基础操作

    旋转:鼠标中键 左右移动:鼠标中键+左shift 放大缩小:鼠标滚轮滚动 blender旋转以锁定物件作为中心点旋转 blender选取物件用鼠标右键, 选中物件之后,利用数字键盘中的点(Del) 来 ...

  2. Android 8.0+ 更新安装apk失败的问题

    最近做项目发现Android 8.0+ 更新安装apk时 出现安装失败的情况  总结原因是 缺少安装的权限 Android 8.0 (Android O)为了针对一些流氓软件引导用户安装其他无关应用. ...

  3. Python __dict__属性详解

    本文转载自 https://www.cnblogs.com/alvin2010/p/9102344.html 感谢 //偏执 大佬 我们都知道Python一切皆对象,那么Python究竟是怎么管理对象 ...

  4. vue中v-model 与 v-bind:value

    之前一直认为,v-model相当于下方代码的语法糖,如下: <h1>{{inputValue}}</h1> <input type="text" :v ...

  5. 当多线程并发遇到Actor

    https://mp.weixin.qq.com/s/mzZatZ10Rh19IEgQvbhGUg

  6. TCP与UDP基本认识及区别

    TCP与UDP基本区别 1.基于连接与无连接 2.TCP要求系统资源较多,UDP较少: 3.UDP程序结构较简单 4.流模式(TCP)与数据报模式(UDP); 5.TCP保证数据正确性,UDP可能丢包 ...

  7. 分享一个14年写的用户管理类-swift版

    AccountManager类 14年设计,从swift 0.9开始,迭代到现在swift4.0版本,总体几乎没什么改动,简单稳定. 其实现的思路主要还是借助之前net反射的经验,实现了自动保存用户信 ...

  8. zabbix3.0监控Windows服务器

    我们下载后,解压开始有多个文件: conf目录存放是agent配置文件bin文件存放windows下32位和64位安装程序 找到conf下的配置文件 zabbix_agentd.win.conf ,修 ...

  9. mktime 夏令时

    我们的最终目的是把字符串格式的时间转换为内部使用的“日历时间”,即到UTC 1970年1月1日零时的秒数.这里就存在夏令时的问题.比如俄罗斯时间2008年10月26日2:30由于夏令时的跳变会经过两次 ...

  10. xpath json操作符说明

    XPath JSONPath Description / $ the root object/element . @ the current object/element / . or [] chil ...