java数据结构第二天

顺序表的实现

顺序表的建立及内部方法:

package liner;

import java.util.Iterator;

public class SequentList<T> implements Iterable<T>{
    //存储元素的数组
    private T[] eles;
    //记录当前顺序表中元素的个数
    private int N;

    //构造方法
    public SequentList(int capacity){
        //初始化数组
        this.eles = (T[])new Object[capacity];
        //初始化长度
        this.N = 0;
    }

    //将一个线性表设置为空表
    public void clear(){
        this.N = 0;
    }

    //判断当前线性表是否为空表
    public boolean isEmpty(){
        return N == 0;
    }

    //获取线性表的长度
    public int length(){
        return N;
    }

    //获取指定位置的元素
    public T get(int i){
        return eles[i];
    }

    //向线性表中添加元素t
    public void insert(T t){
        eles[N++] = t;
    }

    //向线性表中插入元素
    public void insert(int i,T t){
        //先把i和后面的元素让位
        N++;
        for (int j = N; j > i; j--){
            eles[j] = eles[j - 1];
        }
        //放入t
        eles[i] = t;
    }

    //删除指定位置i处的元素,并返回该元素
    public T remove(int i){
        //记录索引i处的值
        T current = eles[i];
        //将后面的元素依次往前移动一位
        for (int index = i; index < N - 1; index++){
            eles[index] = eles[index + 1];
        }
        N --;
        return current;
    }

    //查找t元素第一次出现的位置
    public int indexOf(T t){
        for (int i = 0; i <= N - 1; i++) {
            if (eles[i].equals(t)){
                return i;
            }
        }
        return -1;
    }

    @Override
    public Iterator<T> iterator() {
        //由于是接口无法直接创建对象,因此使用内部类实现该接口
        return new SIterator();
    }

    private class SIterator implements Iterator{
        //使用一个私有变量作为指针去遍历数组
        private int crsor;
        //使用构造方法将指针初始化为0
        public SIterator(){
            this.crsor=0;
        }
        @Override
        public boolean hasNext() {
            return crsor < N;
        }

        @Override
        public Object next() {
            return eles[crsor++];
        }
    }
}

链表

类名Node
构造方法Node(T t, Node next):创建Node对象
成员变量T item: 存储数据 ; Node next:指向下一个结点

单链表

package liner;

import java.util.Iterator;

/*
构造方法:LinkList():创建linklist对象
成员方法:
1.public void clear():置空线性表
2.public boolean isEmpty()判断链表是否为空,是则返回true
3.public int length():获取线性表中元素的个数
4.public T get(int i)读取并返回线性表中第i个元素的值
5.public void insert(T t):往线性表中添加一个元素
6.public void insert(T t, int i)往线性表中的第i个元素之间的位置插入一个值为t的元素
7.public T remove(int i):删除并返回线性表中第i个元素的值
8.public int indexOf(T t):返回线性表中首次出现的值为t的元素的索引
成员内部类:
private class Node<T>: 节点类
成员变量:
1.private Node head: 记录首节点
2.private int N: 记录链表的长度
 */
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;
        //元素个数为0
        N = 0;
    }

    //获取链表的长度
    public int length(){
        return N;
    }

    //判断链表是否为空
    public boolean isEmpty(){
        return N == 0 && head.next == null;
    }

    //获取指定位置i处的元素
    public T get(int i){
        //通过循环,从头结点开始往后找,依次找i次,就可以找到对应的元素
        Node n = head.next;
        for (int index = 0; index < i; index++){
            n = n.next;
        }
        return n.item;
    }

    //向链表中添加元素t
    public void insert(T t){
        //找到当前最后一个节点
        Node n = head;
        while (n.next != null){
            n = n.next;
        }
        //创建新节点,保存元素t
        Node newNode = new Node(t, null);
        //让当前最后一个结点指向新节点
        n.next = newNode;
        //节点元素个数++
        N++;
    }

    //向链表中指定位置i插入元素t
    public void insert(int i, T t){
//        Node n = head.next;
//        Node newNode = new Node(t, null);
//        if (i == 0){
//            head.next = newNode;
//            newNode.next = n.next;
//        }
//        //找到i位置的前面一个节点
//        for (int index = 0; index < i - 1; index++ ){
//            n = n.next;
//        }
//        newNode.next = n.next;
//        n.next = newNode;
        //找到i位置的前一个结点
        Node pre = head;
        for (int index = 0; index <= i - 1; index++){
            pre = pre.next;
        }
        //找到i位置的结点
        Node cur = pre.next;
        Node newNode = new Node(t, cur);
        pre.next = newNode;
        N++;
    }

    //删除指定位置i处的元素,并返回被删除的元素
    public T remove(int i){
        Node pre = head;
        //找到i-1位置处的结点
        for (int index = 0; index <= i -1; index++){
            pre = pre.next;
        }
        Node curr = pre.next;
        pre.next = curr.next;
        N--;
        return curr.item;
    }

    //查找元素t在链表中第一次出现的位置
    public int indexOf(T t){
        //从头结点开始,依次找到每一个节点,取出item和t比较,如果相同,则找到了
        Node n = head.next;
        for (int index = 0; index < N; index ++){
            if (n.item == t) return index;
            else n = n.next;
        }
        return -1;
    }

    @Override
    public Iterator iterator() {
        //由于接口无法创建对象,因此使用内部类
        return new SIterator();
    }

    private class SIterator implements Iterator{
        //使用一个私有变量作为指针去遍历数
        private Node cursor;
        //使用构造方法将指针初始化为0
        public SIterator(){
            //指针初始值为0
            this.cursor = head;
        }

        @Override
        public boolean hasNext() {
            //指针小于N-1则成立
            return cursor.next != null;
        }

        @Override
        public Object next() {
            cursor  = cursor.next;
            return cursor.item;
        }
    }
}

双向链表

类名Node
构造方法Node(T t, Node pre, Node next):创建Node对象
成员变量T item;存储数据 Node next;指向下一个结点 Node pre 指向上一个结点
package Test;

import liner.LinkList;
import liner.TwoWayLinkList;

public class TwoWayLinkListTest {
    public static void main(String[] args) {
        TwoWayLinkList<String> lst = new TwoWayLinkList<>();
        lst.insert("张三");
        lst.insert("李四");
        lst.insert("王五");
        lst.insert(1, "赵六");
//        for (int i = 0; i < lst.length(); i++){
//            System.out.println(lst.get(i));
//        }
        for (String s : lst) {
            System.out.println(s);
        }

        String removeResult = lst.remove(1);
        System.out.println("被移除的元素为:" + removeResult);
        System.out.println("第一个元素是:" + lst.getFirst());
        System.out.println("最后一个元素是:" + lst.getLast());
        lst.clear();
        System.out.println("被清空后的链表的元素个数为:" + lst.length());
    }
}

链表的反转

public void reserve():对整个链表进行反转
public Node reverse(Node curr): 反转链表中的某个结点curr,并把反转后的curr结点返回。
使用递归可以完成反转,递归反转其实就是从原链表的第一个存数据的结点开始,依次调用反转的每一个结点,知道最后一个结点反转完毕,整个链表就反转完毕。

//用来反转整个链表
    public void reverse(){
        //判断当前链表是否为空,如果是,则结束运行,不是则调用重载的reverse方法
        if (isEmpty()){
            return;
        }
        reverse(head.next);
    }

    //用来反转单个结点,这里的pre指的是反转后的pre
    public Node reverse(Node curr){
        if (curr.next == null){
            head.next = curr;
            return curr;
        }
        //递归的反转当前结点的下一节点,返回值就是链表反转后,当前结点的上一个结点
        Node pre = reverse(curr.next);
        //让返回结点的下一个结点变成当前结点curr
        pre.next = curr;
        //把当前结点的下一个结点变为空
        curr.next = null;
        return curr;
    }

快慢指针

快慢指针指的是定义两个指针,这两个指针移动速度一快一慢,一次来制造出自己想要的差值,这个差值可以使我们找到链表相应的结点。一般情况下,快指针的移动步长为满指针的两倍。
1.使用快慢指针得到链表的中间值

public class FastSlowTest {
    public static void main(String[] args) {
        Node<String> seven = new Node<>("gg", null);
//        Node<String> six= new Node<>("ff", seven);
        Node<String> five = new Node<>("ee", null);
        Node<String> four = new Node<>("dd", five);
        Node<String> three = new Node<>("cc", four);
        Node<String> second = new Node<>("bb", three);
        Node<String> first = new Node<>("aa", second);

        //查找中间值
        String mid = getMid(first);
        System.out.println("中间值为:" + mid);
    }

    //first为链表的首节点,返回值为链表的中间结点的值
    public static String getMid(Node<String> first){
        //定义两个指针
        Node fast = first;
        Node slow = first;
        //使用两个指针遍历链表,当快指针没有下一个结点时,就可以结束,此时慢指针指向的结点为中间值
        while (fast.next != null && fast != null){
            fast = fast.next.next;
            slow = slow.next;
        }

        return String.valueOf(slow.item);
    }

    //定义结点类
    private static class Node<T>{
        //存储数据
        T item;
        //下一个结点
        Node next;
        public Node(T item, Node next){
            this.item = item;
            this.next = next;
        }
    }
}

2.使用快慢指针解决是否有环以及环的入口
当快慢指针相遇时,我们可以确定链表中有环,这是重新设定一个新指针指向链表的起点,且步长与慢指针一样为1,则慢指针与新指针相遇的地方就是环的入口。

public class CircleListCheckTest {
    public static void main(String[] args) {
        Node<String> seven = new Node<>("gg", null);
        Node<String> six= new Node<>("ff", seven);
        Node<String> five = new Node<>("ee", six);
        Node<String> four = new Node<>("dd", five);
        Node<String> three = new Node<>("cc", four);
        Node<String> second = new Node<>("bb", three);
        Node<String> first = new Node<>("aa", second);

        //产生环
        seven.next = three;

        //判断是否有环
        boolean circle = isCircle(first);
        if (circle){
            System.out.println("有环");
            //查找有环链表的入口
            Node entrance = getEntrance(first);
            System.out.println("环的入口元素为:" + entrance.item);
        }
        else System.out.println("没有环");



    }

    //查找有环链表的入口结点
    public static Node getEntrance(Node<String> first){
        Node fast = first;
        Node slow = first;
        Node newNode = first;
        while (fast.next != null && fast != null){
            fast = fast.next.next;
            slow = slow.next;
            if (fast == slow){
                break;
            }
        }
        while (newNode != slow){
            newNode = newNode.next;
            slow = slow.next;
        }
        return newNode;
    }

    //first为链表的首节点,返回值为链表的中间结点的值
    public static boolean isCircle(Node<String> first){
        //定义两个指针
        Node fast = first;
        Node slow = first;
        //使用两个指针遍历链表,当快指针没有下一个结点时,就可以结束,此时慢指针指向的结点为中间值
        while (fast.next != null && fast != null){
            fast = fast.next.next;
            slow = slow.next;
            if (fast == slow){
                return true;
            }
        }
        return false;
    }

    //定义结点类
    private static class Node<T>{
        //存储数据
        T item;
        //下一个结点
        Node next;
        public Node(T item, Node next){
            this.item = item;
            this.next = next;
        }
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值