数据结构之线性表的两种存储方式

数组

1.数组是有限个相同类型的变量所组成的有序集合,数组中每一个变量称为元素.特点是在内存中的顺序存储.
2.Java内置数组的特点:
(1)长度一旦确定就不能更改(扩容和缩容都要重新创建一个新的数组,把元素放入其中)
(2)只能存储同一类型的数据
(3)数组中的每个存储空间大小一致且地址连续
(4)提供角标的方式访问数组

线性表

线性表中元素之间关系是一对一的关系(除了第一个和最后一个元素外,其他元素都是首尾相接的),本质为数据结构中的逻辑结构.
1.线性表的顺序存储结构(用数组存储)
(1)定义:用一段地址连续的存储单元依次存储线性表的数据元素.
(2)操作:
增:void add(int index,E e)//在线性表中的index角标处插入E类型的元素e
删:E remove(int index)//删除并返回线性表中角标index处的元素.
查:boolean contains(E e)//判断线性表中是否包含元素e
int find(E e)//查找元素e的角标
改:void set(int index,E e )//修改线性表角标index处的元素为新元素e.
(3)代码:

package DS01.动态数组;
/*
定义线性表的接口List
List支持泛型E
该List线性表中所存储的具体数据类型由外界决定
*/
public interface List<E> extends Iterable<E>{
    int getSize();//获取线性表中元素的有效个数
    boolean isEmpty();//判断线性表是否为空表
    void add(int index,E e); //在线性表指定的index角标处插入元素e
    void addFirst(E e);//在线性表的表头处插入元素e
    void addLast(E e);//在线性表的表位处插入元素e
    E get(int index); //获取线性表中指定角标index处的元素
    E getFirst();//获取表头元素
    E getLast();//获取表尾元素
    void set(int index,E e);//修改线性表中角标index处的元素为新元素e
    boolean contains(E e);//判断线性表中是否包含元素e
    int find(E e);//查找元素e的角标(从左到右默认第一个出现的元素角标)
    E remove(int index);//删除并返回线性表中指定角标index处的元素
    E removeFirst(); //删除并返回表头元素
    E removeLast();//删除并返回表尾元素
    void removeElement(E e);//删除指定元素e
    void clear();//清空线性表
}


package DS01.动态数组;

import java.util.Iterator;

/*
创建线性表List的顺序存储结构实现类ArrayList
*/
public class ArrayList<E> implements List<E>{
    //创建E类型的一维数组
    private E[] data;
    //维护元素个数
    private int size;
    //默认最大容量为10
    private static int DEFAULT_CAPACITY=10;

    //创建一个默认大小的顺序表
    public ArrayList(){
        this(DEFAULT_CAPACITY);
    }

    //创建一个容量由用户指定的顺序表
    public ArrayList(int capacity){
        if(capacity<=0){
            throw new IllegalArgumentException("容量>0:"+capacity);
        }
        data=(E[])(new Object[capacity]);
        size=0;
    }

    //用户传入一个数组 将该数组封装成一个顺序表
    public ArrayList(E[] data){
        if(data==null){
            throw new IllegalArgumentException("数组不能为空");
        }
        this.data=(E[])(new Object[data.length]);
        for (int i = 0; i <data.length ; i++) {
            this.data[i]=data[i];
        }
        size=data.length;
    }

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

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

    @Override
    public void add(int index, E e) {
        if(index<0||index>size){
            throw new IllegalArgumentException("角标越界");
        }
        if(size==data.length){
            //扩容
            resize(data.length*2);
        }
        for (int i = size; i >index ; i--) {
            data[i]=data[i-1];
        }
        data[index]=e;
        size++;
    }

    private void resize(int newLength) {
        E[] newData=(E[])(new Object[newLength]);
        for (int i = 0; i < size; i++) {
            newData[i]=data[i];
        }
        data=newData;
    }

    @Override
    public void addFirst(E e) {
        add(0,e);
    }

    @Override
    public void addLast(E e) {
        add(size,e);
    }

    @Override
    public E get(int index) {
        if(isEmpty()){
            throw new IllegalArgumentException("线性表为空");
        }
        if(index<0||index>=size){
            throw new IllegalArgumentException("角标越界");
        }
        return data[index];
    }

    @Override
    public E getFirst() {
        return get(0);
    }

    @Override
    public E getLast() {
        return get(size-1);
    }

    @Override
    public void set(int index, E e) {
        if(isEmpty()){
            throw new IllegalArgumentException("线性表为空");
        }
        if(index<0||index>=size){
            throw new IllegalArgumentException("角标越界");
        }
        data[index]=e;
    }

    @Override
    public boolean contains(E e) {
        return find(e)!=-1;
    }

    @Override
    public int find(E e) {
        if(isEmpty()){
            throw new IllegalArgumentException("线性表为空");
        }
        for (int i = 0; i < size; i++) {
            if(data[i].equals(e)){
                return i;
            }
        }
        return -1;
    }

    @Override
    public E remove(int index) {
        if(isEmpty()){
            throw new IllegalArgumentException("线性表为空");
        }
        if(index<0||index>=size){
            throw new IllegalArgumentException("角标越界");
        }
        E ret=data[index];
        for(int i=index+1;i<size;i++){
            data[i-1]=data[i];
        }
        size--;
        if(size<=data.length/4&&data.length/2>=10){
            resize(data.length/2);
        }
        return ret;
    }

    @Override
    public E removeFirst() {
        return remove(0);
    }

    @Override
    public E removeLast() {
        return remove(size-1);
    }

    @Override
    public void removeElement(E e) {
        int index=find(e);
        if(index!=-1){
            remove(index);
        }else{
            throw new IllegalArgumentException("元素不存在");
        }
    }

    @Override
    public void clear() {
        size=0;
        data=(E[])(new Object[DEFAULT_CAPACITY]);
    }

    public int getCapacity(){
        return data.length;
    }

    @Override
    public String toString() {
        StringBuilder sb=new StringBuilder();
        sb.append(String.format("ArrayList: %d/%d \n",size,data.length));
        sb.append('[');
        if(isEmpty()){
            sb.append(']');
        }else{
            for (int i = 0; i < size; i++) {
                sb.append(data[i]);
                if(i == size - 1){
                    sb.append(']');
                }else{
                    sb.append(',');
                }
            }
        }
        return sb.toString();
    }

    //返回当前数据结构的一个迭代器对象
    //迭代器用于在没有角标支持的环境下遍历元素
    @Override
    public Iterator<E> iterator() {
        return new ArrayListIterator();
    }
    private class ArrayListIterator implements Iterator{
        private int index=-1;
        @Override
        public boolean hasNext() {
            return index<size-1;
        }

        @Override
        public E next() {
            index++;
            return data[index];
        }
    }
}

测试:

package DS01.动态数组;
public class TestArrayList {
ArrayList<String> arrayList = new ArrayList<>();
        arrayList.addLast("3");
        arrayList.addLast("3");
        arrayList.add(0,"1");
        arrayList.add(2,"2");
        System.out.println(arrayList);
        System.out.println(arrayList.remove(2));
        System.out.println(arrayList);
}

结果:
ArrayList: 4/10
[1,3,2,3]
2
ArrayList: 3/10
[1,3,3]

2.线性表链式存储(用链表存储)
(1)定义:为了表示每个数据元素ai与其直接后继数据元素ai+1之间的逻辑关系,对数据元素ai来说,除了存储其本身的信息之外,还需存储一个指示其直接后继的信息(即直接后继的存储位置).我们把存储数据元素信息的域称为数据域,把存储直接后继位置的域称为指针域.指针域中存储的信息称做指针或链.这两部分信息组成数据元素ai的存储映像,称为结点(Node).n个结点(a的存储映像)链结成一个链表,即为线性表(a1,a2,…,an)的链式存储结构,因为此链表的每个结点中只包含一个指针域,所以叫做单链表.
在这里插入图片描述
在这里插入图片描述
(2)头结点与头指针
头结点是指链表的第一个节点,有真实节点和虚拟头结点两种.
真实头结点:第一个节点存储数据
在这里插入图片描述
虚拟头结点:第一个节点不存储数据
在这里插入图片描述
头指针:一个引用变量,存储头结点地址的指针
尾指针:一个引用变量,存储最后一个节点地址的指针
(3)操作:
增:void add(int index,E e)//在线性表中的index角标处插入E类型的元素e
删:E remove(int index)//删除并返回线性表中角标index处的元素.
查:boolean contains(E e)//判断线性表中是否包含元素e
int find(E e)//查找元素e的角标
改:void set(int index,E e )//修改线性表角标index处的元素为新元素e.
(4)代码:

package DS01.动态数组;
/*
定义线性表的接口List
List支持泛型E
该List线性表中所存储的具体数据类型由外界决定
*/
public interface List<E> extends Iterable<E>{
    int getSize();//获取线性表中元素的有效个数
    boolean isEmpty();//判断线性表是否为空表
    void add(int index,E e); //在线性表指定的index角标处插入元素e
    void addFirst(E e);//在线性表的表头处插入元素e
    void addLast(E e);//在线性表的表位处插入元素e
    E get(int index); //获取线性表中指定角标index处的元素
    E getFirst();//获取表头元素
    E getLast();//获取表尾元素
    void set(int index,E e);//修改线性表中角标index处的元素为新元素e
    boolean contains(E e);//判断线性表中是否包含元素e
    int find(E e);//查找元素e的角标(从左到右默认第一个出现的元素角标)
    E remove(int index);//删除并返回线性表中指定角标index处的元素
    E removeFirst(); //删除并返回表头元素
    E removeLast();//删除并返回表尾元素
    void removeElement(E e);//删除指定元素e
    void clear();//清空线性表
}


package Ds02.动态链表;
import java.util.Iterator;
public class LinkedList<E> implements List<E> {
    private Node head;  //链表的头指针(虚头结点)
    private Node rear;  //链表的尾指针
    private int size;   //链表的元素个数(结点个数)

    public LinkedList(){
        head=new Node();
        rear=head;
    }


    private class Node{
        E data;     //数据域
        Node next;  //指针域
        Node(){
            this(null,null);
        }
        Node(E data,Node next){
            this.data=data;
            this.next=next;
        }

        @Override
        public String toString() {
            return data.toString();
        }
    }


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

    @Override
    public boolean isEmpty() {
        return size==0&&head==rear;
    }

    @Override
    public void add(int index, E e) {
        if(index<0||index>size){
            throw new IllegalArgumentException("角标越界");
        }
        Node n=new Node();
        n.data=e;
        if(isEmpty()){          //空表状态 特殊处理
            head.next=n;
            rear=n;
        }else if(index==0){     //头插法
            n.next=head.next;
            head.next=n;
        }else if(index==size){  //尾插法
            rear.next=n;
            rear=n;
        }else{                  //中间插
            Node p=head;
            for(int i=0;i<index;i++){
                p=p.next;
            }
            n.next=p.next;
            p.next=n;
        }
        size++;
    }

    @Override
    public void addFirst(E e) {
        add(0,e);
    }

    @Override
    public void addLast(E e) {
        add(size,e);
    }

    @Override
    public E get(int index) {
        if(isEmpty()){
            throw new IllegalArgumentException("空表");
        }
        if(index<0||index>=size){
            throw new IllegalArgumentException("角标越界");
        }
        if(index==0){
            return head.next.data;
        }else if(index==size-1){
            return rear.data;
        }else{
            Node p=head;
            for(int i=0;i<=index;i++){
                p=p.next;
            }
            return p.data;
        }
    }

    @Override
    public E getFirst() {
        return get(0);
    }

    @Override
    public E getLast() {
        return get(size-1);
    }

    @Override
    public void set(int index, E e) {
        if(isEmpty()){
            throw new IllegalArgumentException("空表");
        }
        if(index<0||index>=size){
            throw new IllegalArgumentException("角标越界");
        }
        Node p=head;
        for(int i=0;i<=index;i++){
            p=p.next;
        }
        p.data=e;
    }

    @Override
    public boolean contains(E e) {
        return find(e)!=-1;
    }

    @Override
    public int find(E e) {
        Node p=head;
        for(int i=0;i<size;i++){
            p=p.next;
            if(p.data.equals(e)){
                return i;
            }
        }
        return -1;
    }

    @Override
    public E remove(int index) {
        if(isEmpty()){
            throw new IllegalArgumentException("表空");
        }
        if(index<0||index>=size){
            throw new IllegalArgumentException("角标越界");
        }
        E ret=null;
        if(size==1){
            ret=rear.data;
            head.next=null;
            rear=head;
        }else if(index==0){
            Node del=head.next;
            ret=del.data;
            head.next=del.next;
            del.next=null;
            del=null;
        }else if(index==size-1){
            Node p=head;
            while(true){
                if(p.next!=rear){
                    p=p.next;
                }else{
                    break;
                }
            }
            ret=p.next.data;
            p.next=null;
            rear=p;
        }else{
            Node p=head;
            for(int i=0;i<index;i++){
                p=p.next;
            }
            Node del=p.next;
            ret=del.data;
            p.next=del.next;
            del.next=null;
            del=null;       // 释放空间 free(del)
        }
        size--;
        return ret;
    }

    @Override
    public E removeFirst() {
        return remove(0);
    }

    @Override
    public E removeLast() {
        return remove(size-1);
    }

    @Override
    public void removeElement(E e) {
        int index=find(e);
        if(index!=-1){
            remove(index);
        }else{
            throw new IllegalArgumentException("找不到!");
        }
    }

    @Override
    public void clear() {
        head.next=null;
        rear=head;
        size=0;
    }

    @Override
    public String toString() {
        StringBuilder sb=new StringBuilder();
        sb.append("LinkedList : "+size+"\n");
        sb.append('[');
        if(isEmpty()){
            sb.append(']');
        }else{
            Node p=head;
            while(true){
                if(p.next!=rear){
                    p=p.next;
                    sb.append(p.data);
                    sb.append(',');
                }else{
                    sb.append(rear.data);
                    sb.append(']');
                    break;
                }
            }
        }
        return sb.toString();
    }

    @Override
    public Iterator<E> iterator() {
        return new LinkedListIterator();
    }
    public class LinkedListIterator implements Iterator<E>{
        private Node p=head;
        @Override
        public boolean hasNext() {
            return p.next!=null;
        }

        @Override
        public E next() {
            p=p.next;
            return p.data;
        }
    }
}

测试:

package Ds02.动态链表;

import java.util.*;
public class TestLinkedList {
	public static void main(String[] args) {
		 LinkedList<Integer> list=new LinkedList<>();
		  list.addLast(2);
		 System.out.println(list);
		 list.addLast(3);
		 System.out.println(list);
		 list.addFirst(1);
		 System.out.println(list);
	}
}

结果:
LinkedList : 1
[2]
LinkedList : 2
[2,3]
LinkedList : 3
[1,2,3]

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值