java实现简单数据结构--线性表

线性表简介

什么是线性表

在《数据结构简明教程》中如此定义,线性表是由n(n>=0)个相同类型数据元素组成的有限序列

线性表是一个逻辑结构的概念,

线性表的性质

  • a[i-1]是a[i]的前驱元素,a[i+1]是a[i]的后继元素
  • 若至少含有一个元素,则只有唯一的开始元素和终端元素,除了开始元素外其他元素有且只有一个前驱元素;除了终端节点外其他元素有且仅有一个后继元素
  • 线性表中每个元素有唯一的序号,同一个线性表中可以存在值相同的多个元素,但他们的序号不相同

存储结构

  • 顺序表
  • 链表

线性表接口

MyList

该接口为整个线性表的抽象,声明了几种常用的方法

使用object类:因为java中所有类都继承object类,所以使用object类可以更加抽象的定义出接口,让其更加适用于所有类型

package com.brozha.datastruct.linearlist;

/**
 * @author brozha
 * @since 2021/4/12
 */
public interface MyList {

    //返回顺序表的长度
    public int size();
    //判断是否为空
    public boolean isEmpty();
    //判断是否包含元素e,如果找到就返回下标(从0开始),如果没找到就返回-1
    public int indexOf(Object e);
    //将数据元素e插入到第i号(i从0开始),将原位置的i后移,成功返回为true,失败返回为false
    public boolean insert(Object e,int i);
    //删除第i个位置上的元素
    public boolean remove(int i);
    //获取第i个元素,获取失败则抛出异常
    public Object get(int i) throws IndexOutOfBoundsException;
    //替换i位置上的值为e,返回失败说明数组越界
    public boolean replace(int i,Object e);


}

顺序表

定义

顺序表是线性表采用顺序存储结构在计算机内存中的存储方式,它由多个连续的存储单元构成,每个存储单元存放线性表的一个元素,逻辑上相邻的数据元素在内存中也是相邻的,不需要额外的内存空间来存放元素之间的逻辑关系。顺序表是线性表的直接映射

也就是说我们可以得出以下公式:

LOC(a[i+1])=LOC(a[i])+K ===> LOC(a[i])=LOC(a[0])+i*K(其中K为每个元素需要占用K个存储单元,LOC代表该元素的存储地址)

MyArrayList实现

package com.brozha.datastruct.linearlist;

import java.util.ArrayList;
import java.util.Arrays;

/**
 * @author brozha
 * @since 2021/4/12
 */
public class MyArrayList implements MyList{

    private static final int DEFAULT_LEN = 8;  //数组默认的大小
    private int size;       //元素个数
    private Object[] elements;      //存放元素的数组


    public MyArrayList(){
        this(DEFAULT_LEN);
    }


    public MyArrayList(int len){
        size = 0;
        elements = new Object[len];
    }



    @Override
    public int size() {
        return size;
    }

    @Override
    public boolean isEmpty() {
        return size>0;
    }

    /**
     *
     * @param e
     * @return  返回第一次出现的下标,-1表示没找到
     */
    @Override
    public int indexOf(Object e) {
        for(int i = 0;i<size;i++){
            if(e.equals(elements[i])){
                return i;
            }
        }
        return -1;
    }

    /**
     * 在下标为i的元素之前插入e
     * @param e
     * @param i     如果i刚好==size,则插入的位置为最后
     * @return  如果插入成功则返回true,下标越界则返回false,越界的意思是在size之后
     *
     */
    @Override
    public boolean insert(Object e, int i) {
        if(i<0||i>size){
            return false;
        }
        //如果已经满了,则先进行扩容
        if(size>=elements.length){
            expandSpace();
        }
        //将i元素以及其之后的元素向后移,再在i处插入e
        for(int j=size;j>i;j--){
            elements[j] = elements[j-1];
        }
        elements[i] = e;
        size++;
        return true;
    }

    @Override
    public boolean remove(int i) {
        if(i<0||i>=size){
            return false;
        }
        for(int j = i;j<size-1;j++){
            elements[j] = elements[j+1];
        }
        size--;
        return true;
    }

    @Override
    public Object get(int i) throws IndexOutOfBoundsException {
        if(i<0||i>=size){
            throw new IndexOutOfBoundsException("下标"+i+"越界了");
        }
        return elements[i];
    }

    @Override
    public boolean replace(int i, Object e) {
        if(i<0||i>=size){
            return false;
        }
        elements[i] = e;
        return true;
    }

    //扩容
    private void expandSpace(){
        //扩容1.5倍
        int newLength = elements.length+(elements.length>>1);
        //也可以用循环手动扩容
        elements = Arrays.copyOf(elements,newLength);
        System.out.println("扩容后的总容量"+elements.length);
    }
}

思考:深拷贝和浅拷贝?Arrays.copyOf是深拷贝还是浅拷贝?

简单测试(简单的测试了一下,测试可能不完全),若有bug请读者告知

package com.brozha.datastruct.linearlist;

/**
 * @author brozha
 * @since 2021/4/12
 */
public class ArrayListTest {
    public static void main(String[] args) {
        MyArrayList mal = new MyArrayList();
        System.out.println("初始的长度为:"+mal.size());
        for(int i=0;i<15;i++){
            mal.insert(i,i);
        }
        System.out.println("插入15个数之后的值:");
        for(int i=0;i<mal.size();i++){
            System.out.print(mal.get(i)+" ");
        }
        System.out.println();
        mal.remove(5);
        System.out.println("删除下标为5的数后:");
        for(int i=0;i<mal.size();i++){
            System.out.print(mal.get(i)+" ");
        }
        System.out.println();
        mal.insert(88,5);
        System.out.println("在下标为5的数前插入88:");
        for(int i=0;i<mal.size();i++){
            System.out.print(mal.get(i)+" ");
        }
        System.out.println();
        System.out.println("数字10第一次出现的下标为:"+mal.indexOf(10));
        System.out.println("数字12312第一次出现的下表为:"+mal.indexOf(12312));

        mal.replace(10,12312);
        System.out.println("将下标为10的数替换为12312:");
        for(int i=0;i<mal.size();i++){
            System.out.print(mal.get(i)+" ");
        }
        System.out.println();
        System.out.println("数字12312第一次出现的下表为:"+mal.indexOf(12312));
    }
}

测试结果

image-20210412233404567

链表

定义

线性表的链式存储结构中每个元素的存储空间作为一个节点单独分配,因此逻辑上相邻的元素对应的节点物理上不一定是相邻的,通过增加指针域表示逻辑关系,在插入和删除操作时只需要修改相应的指针域,从而克服了顺序表中插入和删除操作需要移动大量元素的弱点,但同时也失去了顺序表可随机存取的优点。

Node类(单链表)

package com.brozha.datastruct.linearlist;

/**
 * @author brozha
 * @since 2021/4/14
 */
public class Node {
    public Object val;
    public Node next;
    public Node(){};
    public Node(Object val){
        this.val = val;
    }
}

单链表实现的线性表

package com.brozha.datastruct.linearlist;

/**
 * @author brozha
 * @since 2021/4/14
 */
public class MyLinkedList implements MyList{


    int size;
    Node node;
    MyLinkedList(){
        size = 0;
        //相当于是有一个头结点的
        node = new Node();
    }

    @Override
    public int size() {
        return size;
    }

    @Override
    public boolean isEmpty() {
        return size>0;
    }

    @Override
    public int indexOf(Object e) {
        Node p = node.next;
        int i = 0;
        while(p!=null){
            if(p.val.equals(e)){
                return i;
            }
            i++;
            p = p.next;
        }
        return -1;
    }

    //将e插入到第i个位置,后面的往后移动
    @Override
    public boolean insert(Object e, int i) {
        if(i<0||i>size){
            return false;
        }
        Node p = node;
        int k = 0;
        while(k<i){
            k++;
            p = p.next;
        }
        Node q = new Node();
        q = p.next;
        p.next = new Node(e);
        p.next.next = q;
        size++;
        return true;
    }

    @Override
    public boolean remove(int i) {
        if(i<0||i>=size){
            return false;
        }
        Node p = node;
        int k = 0;
        while(k<i){
            k++;
            p = p.next;
        }
        p.next = p.next.next;
        size--;
        return true;
    }

    @Override
    public Object get(int i) throws IndexOutOfBoundsException {
        if(i<0||i>=size){
            throw new IndexOutOfBoundsException(i+"越界了!!!");
        }
        Node p = node.next;
        int k = 0;
        while(k<i){
            k++;
            p = p.next;
        }
        return p.val;
    }

    @Override
    public boolean replace(int i, Object e) {
        if(i<0||i>=size){
            return false;
        }
        Node p = node.next;
        int k = 0;
        while(k<i){
            k++;
            p = p.next;
        }
        p.val = e;
        return true;
    }

    @Override
    public void add(Object e) {
        //头插法
        Node p = new Node(e);
        p.next = node.next;
        node.next = p;
        size++;
    }
}

测试类

package com.brozha.datastruct.linearlist;

/**
 * @author brozha
 * @since 2021/4/12
 */
public class ListTest {
    public static void main(String[] args) {
        MyList mal = new MyLinkedList();
        System.out.println("初始的长度为:"+mal.size());
        for(int i=0;i<15;i++){
            mal.insert(i,i);
        }
        System.out.println("插入15个数之后的值:");
        for(int i=0;i<mal.size();i++){
            System.out.print(mal.get(i)+" ");
        }
        System.out.println();
        mal.remove(5);
        System.out.println("删除下标为5的数后:");
        for(int i=0;i<mal.size();i++){
            System.out.print(mal.get(i)+" ");
        }
        System.out.println();
        mal.insert(88,5);
        System.out.println("在下标为5的数前插入88:");
        for(int i=0;i<mal.size();i++){
            System.out.print(mal.get(i)+" ");
        }
        System.out.println();
        System.out.println("数字10第一次出现的下标为:"+mal.indexOf(10));
        System.out.println("数字12312第一次出现的下表为:"+mal.indexOf(12312));

        mal.replace(10,12312);
        System.out.println("将下标为10的数替换为12312:");
        for(int i=0;i<mal.size();i++){
            System.out.print(mal.get(i)+" ");
        }
        System.out.println();
        System.out.println("数字12312第一次出现的下表为:"+mal.indexOf(12312));
    }
}

image-20210414004437443

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值