Java实现链表的常见操作算法详解

所属分类: 软件编程 / java 阅读数: 32
收藏 0 赞 0 分享

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

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

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

单链表的结构:

在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();
  }
}

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持脚本之家。

更多精彩内容其他人还在看

Springmvc restful配置遇到的小坑

本文是小编给大家带了的Springmvc restful配置遇到的小小坑,小编给大家带来了问题原因及解决办法,非常不错,具有参考借鉴价值,感兴趣的朋友一起看下吧
收藏 0 赞 0 分享

Java中的匿名内部类小结

java内部类分为: 成员内部类、静态嵌套类、方法内部类、匿名内部类。这篇文章主要介绍了Java中的匿名内部类的相关资料,需要的朋友可以参考下
收藏 0 赞 0 分享

Java的云打印Lodop

这篇文章主要介绍了Java的云打印Lodop 的相关资料,非常不错,具有参考借鉴价值,需要的朋友可以参考下
收藏 0 赞 0 分享

Java线程池框架核心代码解析

这篇文章主要针对Java线程池框架核心代码进行详细解析,分析Java线程池框架的实现ThreadPoolExecutor,感兴趣的小伙伴们可以参考一下
收藏 0 赞 0 分享

Java 交换两个变量的数值实现方法

下面小编就为大家带来一篇Java 交换两个变量的数值实现方法。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
收藏 0 赞 0 分享

全面了解JAVA_BaseDAO数据处理类

下面小编就为大家带来一篇全面了解JAVA_BaseDAO数据处理类。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
收藏 0 赞 0 分享

java、python、JavaScript以及jquery循环语句的区别

本篇文章主要介绍java、python、JavaScript以及jquery的循环语句的区别,这里整理了它们循环语句语法跟示例,以便大家阅读,更好的区分它们的不同
收藏 0 赞 0 分享

基于JDBC封装的BaseDao(实例代码)

下面小编就为大家带来一篇基于JDBC封装的BaseDao(实例代码)。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
收藏 0 赞 0 分享

简单通用JDBC辅助类封装(实例)

下面小编就为大家带来一篇简单通用JDBC辅助类封装(实例)。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
收藏 0 赞 0 分享

浅谈java线程中生产者与消费者的问题

下面小编就为大家带来一篇浅谈java线程中生产者与消费者的问题。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
收藏 0 赞 0 分享
查看更多