目录
节点API设计
类名 | Node<T> |
构造方法 | Node(T t,Node next);创建Node对象 |
成员变量 | T item:存储数据<br/> Node next:指向下一个节点 |
节点类实现
package test.lianbiao; import org.apache.poi.ss.formula.functions.T; public class Node { public T item; public Node next; public Node(T item, Node next) { this.item = item; this.next = next; } }
1.2.1 单向链表
1.2.1.2,单向链表代码实现
package test.linear;
import bsh.This;
import org.apache.poi.ss.formula.functions.T;
import java.util.Iterator;
public class LinkList <T> implements Iterable<T>{
//记录头结点
private Node head;
//记录链表的长度
private int N;
private class Node{
T item;
Node next;
public Node(T item,Node next){
this.item = item;
this.next = next;
}
}
public LinkList(){
//初始化头结点
this.head = new Node(null,null);
//初始化元素个数
this.N = 0;
}
//清楚链表
public void clear(){
head.next = null;
this.N = 0;
}
//获取链表的长度
public int length(){
return N;
}
//判断链表是否为空
public boolean isEmpty(){
return N==0;
}
//获取指定位置的元素
public T get(int i){
//通过循环,从头结点开始往后找,依次找i次,就可以找到对应的元素
Node n = head.next;
for (int index = 0; index < i; index++) {
n = n.next;
}
return n.item;
}
//向链表添加元素
public void insert(T t){
Node n = head;
//找到当前最后一个结点
while(n.next!=null){
n = n.next;
}
//创建新节点
Node newNode = new Node(t,null);
//让当前最后一个结点指向新节点
n.next = newNode;
//元素个数加1
N++;
}
//向指定位置i处添加元素t
public void insert(int i , T t){
//找到i位置前一个节点
Node pro = head;
for (int index = 0; index <= i-1 ; index++) {
pro = pro.next;
}
//找到i位置的节点
Node curr = pro.next;
//创建新节点,并且新节点需要指向原来位置的i节点
Node newNode = new Node(t,curr);
//原来i位置的前一个节点要指向新节点即可
pro.next = newNode;
N++;
}
//删除指定位置i处的元素,并返回被删除的元素
public T remove(int i ){
//找到i位置前一个节点
Node pro = head;
for (int index = 0; index < i ; index++) {
pro = pro.next;
}
//找到i位置的节点
Node curr = pro.next;
//原来i位置的前一个节点要指向i位置的后一个节点即可
pro.next = curr.next;
N--;
return curr.item;
}
//删除指定位置i处的元素,并返回被删除的元素
public int indexOf(T t){
//从头结点开始,依次找到每一个节点,取出item,如果相同,就找到了
Node n = this.head;
for (int i=0;n.next!=null;i++){
n=n.next;
if(n.item.equals(t)){
return i;
}
}
return -1;
}
@Override
public Iterator<T> iterator() {
return new Literator();
}
private class Literator implements Iterator {
private Node n;
public Literator(){
this.n = head ;
}
@Override
public boolean hasNext() {
return n.next!=null;
}
@Override
public Object next() {
n = n.next;
return n.item;
}
@Override
public void remove() {
}
}
}
测试代码
package test.linear;
public class ListListTest {
public static void main(String[] args) {
LinkList<String> list1 = new LinkList<>();
list1.insert("姚明");
list1.insert("科比");
list1.insert("麦迪");
list1.insert(1,"詹姆斯");
for (String s : list1) {
System.out.println(s);
}
System.out.println("------------------------------------------");
String geyResult = list1.get(1);
System.out.println("获取索引1处的结果为"+geyResult);
//测试删除
String removeResult = list1.remove(0);
System.out.println("删除获取索引0处的结果为"+removeResult);
}
}
执行结果
姚明
詹姆斯
科比
麦迪
------------------------------------------
获取索引1处的结果为詹姆斯
删除获取索引0处的结果为姚明
1.2.2 双向链表
代码实现:
代码有问题,没找到错的地方
package test.linear;
import org.apache.poi.ss.formula.functions.T;
import java.util.Iterator;
public class TwoWayLinkList <T> implements Iterable<T>{
//首节点
private Node head;
//最后一个节点
private Node last;
//链表的长度
private int N;
//节点类
private class Node{
//存储数据
public T item;
//指向上一个节点
public Node pre;
//指向下一个节点
public Node next;
public Node(T item, Node pre, Node next){
this.item = item;
this.pre = pre;
this.next = next;
}
}
public TwoWayLinkList(){
//初始化头结点和尾结点
this.head = new Node(null,null,null);
//初始化元素个数
this.last = null;
//初始化元素个数
this.N = 0;
}
//清空链表
public void clear(){
this.head.next = null;
this.head.pre = null;
this.head.item = null;
this.last = null;
this.N = 0;
}
//获取链表长度
public int length(){
return N;
}
//判断链表是否为空
public boolean isEmpty(){
return N==0;
}
//获取第一个元素
public T getFirst(){
if(isEmpty()){
return null;
}
return head.next.item;
}
//获取最后一个元素
public T getLast(){
if(isEmpty()){
return null;
}
return last.item;
}
//插入元素
public void insert(T t){
if(isEmpty()){
//如果链表为空
//创建新节点
Node newNode = new Node(t,head,null);
//让新节点成为尾结点
last = newNode;
//让头节点指向尾结点
head.next = last;
}else{
//如果链表不为空
Node olaLast = last;
//创建新的节点
Node newNode = new Node(t,olaLast,null);
//让当前的尾结点指向新节点
olaLast.next = newNode;
//让新节点称为尾结点
last = newNode;
}
//元素个数+1
N++;
}
//向指定位置i处插入元素t
public void insert(int i,T t ){
//找到i位置的前一个结点
Node pre = head;
for(int index=0;index<i;index++){
pre = pre.next;
}
//找到i位置的节点
Node curr = pre.next;
//创建新节点
Node newNode = new Node(t,pre,curr);
//让i位置的前一个结点的下一个节点变为新的节点
pre.next = newNode;
//让i位置的前一个结点变为新结点
curr.pre = newNode;
//元素个数加一
N++;
}
//获取指定位置i处的元素
public T get(int i){
Node n = head.next;
for(int index = 0;index<i;index++){
n = n.next;
}
return n.item;
}
//找到元素t在链表中第一次出现的位置
public int indexOf(T t){
Node n = head;
for(int index = 0;n.next!=null ;index++){
n = n.next;
if(n.next.equals(t)){
return index;
}
}
return -1;
}
public T remove(int i){
//找到i处元素的前一个节点
Node pre = this.head;
for (int index = 0;index < i;index++){
pre = pre.next;
}
//找到i处元素的节点
Node curr = pre.next;
//找到i处元素的下一个节点
Node nextNode = curr.next;
//前一个节点指向i节点的后一个节点
pre.next = nextNode;
//i节点后一个一个节点指向i节点的后一个节点
nextNode.pre = pre;
//元素个数减一
N--;
return curr.item;
}
@Override
public Iterator<T> iterator() {
return new TIterator();
}
private class TIterator implements Iterator{
private Node n;
public TIterator (){
this.n = head;
}
@Override
public boolean hasNext() {
return n.next==null;
}
@Override
public Object next() {
n=n.next;
return n.item;
}
@Override
public void remove() {
}
}
}
1.2.2.4 java 中LinkedList实现
java中LinkedList 集合也是使用双向链表实现,并提供了增删盖茶的相关方法。
1.2.3 链表复杂度分析
查询比较多用顺序表,增删操作比较多用链表
1.2.4 链表反转
下面的代码不知道哪里有问题,执行结果不对,尴尬
//用来反转整个链表
public void reverse(){
if(isEmpty()){
return;
}
reverse(head.next);
}
//反转指定的结点,并把反转后的结点返回
public Node reverse(Node curr){
if(curr.next == null){
this.head = curr;
return curr;
}
//递归的反转当前结点curr的下一个结点;返回值就是链表反转后,当前结点的上一个结点
Node pre = reverse(curr.next);
//让返回的节点的下一个结点变成当前结点curr;
pre.next = curr;
//把当前结点的下一个结点变成null
curr.next = null;
return curr;
}
1.2.5 快慢指针
快满指针指的是定义俩个指针,这俩个指针的移动速度一快一慢,以此来制造自己想要的差值,这个差值可以让我们找到链表上相应的结点。一般情况下,快指针的移动步长为慢指针的俩倍。
package test.linear;
import
import org.apache.poi.ss.formula.functions.T;
public class TES1 {
public static void main(String[] args) {
Node<String> first = new Node<String>("aa",null);
Node<String> second = new Node<String>("bb",null);
Node<String> third = new Node<String>("cc",null);
Node<String> four = new Node<String>("dd",null);
Node<String> five = new Node<String>("ee",null);
Node<String> six = new Node<String>("ff",null);
Node<String> seven = new Node<String>("gg",null);
//完成结点之间的指向
first.next=second;
second.next=third;
third.next=four;
four.next=five;
five.next=six;
six.next=seven;
//查找中间值
String mid = getMid(first);
System.out.println("中间值为:"+mid);
}
/**
*
* @param first 链表的首结点
* @return 链表中中间结点的值
*/
public static String getMid(Node<String> first){
//定义俩个指针
Node<String> fast = first;
Node<String> slow = first;
//使用俩个指针遍历链表,当快指针指向的结点没有下一个结点了,就可以结束了。
while(fast!=null && fast.next!=null){
fast = fast.next.next;
slow = slow.next;
}
return slow.item;
}
private static class Node<T>{
T item;
Node next;
public Node(T item,Node next){
this.item = item;
this.next = next;
}
}
}
中间值为:dd
单链表是否有环问题
如果是有环的,那么快指针总会追上慢指针,如果是无环的,那么久永远追不上
public static boolean isCircle(Node<String> first){
//定义俩个指针
Node<String> fast = first;
Node<String> slow = first;
//使用俩个指针遍历链表,当快指针指向的结点没有下一个结点了,就可以结束了。
while(fast!=null && fast.next!=null){
fast = fast.next.next;
slow = slow.next;
if(fast.equals(slow)){
return true;
}
}
return false;
}