算法-线性表-链表

目录

1.2.1 单向链表

1.2.2 双向链表

1.2.3 链表复杂度分析


节点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;
    }

1.2.6 循环链表

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值