CS61B:线性表

本文详细介绍了使用Java实现顺序表和链表的数据结构,包括它们的构造方法、主要操作和时间复杂度分析。对比了顺序表与链表在扩展性、插入/删除操作和随机访问性能上的优劣,以及对内存和缓存利用的影响。
摘要由CSDN通过智能技术生成

线性表

  • 本线性表包含顺序表和链表,使用java实现该数据结构
  • 都使用泛型使得线性表可以容纳任何类型的数据
  • 表现了顺序表以及链表的特性,以及技巧性的实现

顺序表

实现方法:

  • public AList() 初始化一个顺序表,顺序表大小为0。
  • public void addLast(Elem x) 在顺序表的末尾添加一个元素,如果超出线性表容量则扩大线性表。
  • public Elem getLast() 获取顺序表的最后一个元素,如果顺序为空,返回null。
  • public Elem get(int i) 获取顺序表的第i个元素,i表示数组下标,如果索引越界,返回null。
  • public int size() 获取顺序表的大小
  • public int removeLast() 删除顺序表的最后一个元素,当数组大部分值为空,则缩小数组容量。
  • rivate void resize(int capacity) 按照capacity调整顺序表的当前容量。

亮点:

  • 所有实现的时间复杂度都是O(1)级别的。
  • 使用了恰当的成员变量,例如使用size缓存当前数组大小,避免通过遍历或者递归
  • 使用RFACTOR系数控制扩展线性表的速度,以免当顺序表容量不足,频繁扩大线性表
public class AList<Elem> {
    private Elem[] item;
    private int size;

    private int RFACTOR = 2;

    /** Creates an empty list. */
    public AList() {
        item = (Elem[]) new Object[100];
        size = 0;
    }

    private void resize(int capacity){
        Elem[] a = (Elem[]) new Object[capacity];
        System.arraycopy(item, 0, a, 0, size);
        item = a;
    }

    /** Inserts X into the back of the list. */
    public void addLast(Elem x) {
        if (size >= item.length) {
            resize(size * RFACTOR); 
        }
        item[size] = x;
        size++;
    }

    /** Returns the item from the back of the list. */
    public Elem getLast() {
        if (size == 0) {
            System.out.println("current list is empty");
            return null;
        }
        return item[size-1];
    }
    /** Gets the ith item in the list (0 is the front). */
    public Elem get(int i) {
        if (i < 0 || i >= size){
            System.out.println("list beyond list bound");
            return null;
        }
        return item[i];
    }

    /** Returns the number of items in the list. */
    public int size() {
        return size;
    }

    /** Deletes item from back of the list and
     * returns deleted item. */
    public int removeLast() {
        if ((double) size /item.length <= 0.25) {
            resize(item.length / RFACTOR);
        }
        item[size-1] = null;
        size--;
        return 0;
    }
}

线性表

实现方法

  • public SLList() 创建一个空链表。
  • public SLList(Elem x) 创建一个有一个元素的链表。
  • public void addFirst(Elem x) 在链表头部添加一个元素。
  • public Elem getFirst() 获取链表头部元素值。
  • public void addLast(Elem x) 在链表尾部添加一个元素。
  • public Elem getLast() 获取链表尾部元素值。
  • public void removeLast() 删除链表尾部元素值。
  • private int size(IntNode p) 获取从元素p开始一直到链表尾部的长度。
  • public int size() 获取链表大小。
  • public String toString() 以恰当的方式打印链表

亮点:

  • 使用内部类表示链表数据结构,将数据结构封装好防止客户从外部篡改链表
  • 使用first以及last缓存当前链表的首部和尾部,方便在O(1)时间内完成大多数操作
public class SLList<Elem> {
    private class IntNode {
        public Elem item;
        public IntNode next;

        public IntNode(Elem i, IntNode n) {
            item = i;
            next = n;
        }
    }
    private IntNode first;

    private int size; //if list too longer,add size as a cache,record the list size.

    private IntNode last; //similar to size

    /**
     * if list is empty, first should is null
     */
    public SLList() {
        first = null;
        last = null;
        size = 0;
    }

    public SLList(Elem x) {
        first = new IntNode(x, null);
        last = first;
        size = 1;
    }

    /**
     * Adds an item to the start of the list.
     */
    public void addFirst(Elem x) {
        first = new IntNode(x, first);
        size = size + 1;
        if (size == 1) {
            last = first;
        }
    }

    /**
     * Retrieves the front item from the list.
     */
    public Elem getFirst() {
        return first.item;
    }

    /**
     * Adds an item to the end of the list.
     */
    public void addLast(Elem x) {
        if (last == null) {
            first = new IntNode(x, null);
            last = first;
            size += 1;
            return;
        }
        last.next = new IntNode(x, null);
        last = last.next;
        size += 1;
    }

    /**
     * Retrieves the last item from the list.
     */
    public Elem getLast() {
        if (last == null) {
            System.out.println("current list is null");
            return null;
        }

        return last.item;
    }

    public void removeLast() {
        IntNode p = first;
        if (last == null) {
            System.out.println("current list is null");
            return;
        }
        if (first.next == null) {
            first = null;
            last = null;
            size = 0;
            return;
        }
        while (p.next.next != null) {
            p = p.next;
        }
        p.next = null;
        size = size - 1;
    }

    /**
     * Returns the size of the list starting at IntNode p.
     */
    private int size(IntNode p) {
        if (p.next == null) {
            return 1;
        }

        return 1 + size(p.next);
    }

    public int size() {
        return size;
    }

    @Override
    public String toString() {
        String result = "[";
        IntNode p = first;
        while (p.next != null){
            result = result + p.item + ",";
            p = p.next;
        }
        result = result + p.item;
        result = result + "]";
        return result;
    }
}

顺序表和链表对比

  • 当顺序表大小不足时,扩展顺序表是一种耗费性能的操作,在此方面,链表强于顺序表。
  • 在线性表头部进行插入删除时,顺序表需要O(n)的时间复杂度,但链表只需要O(1)的时间复杂度。
  • 在随机获取线性表的元素时,链表需要O(n)的时间复杂度,而顺序表只需要O(1)的时间复杂度。
  • 顺序表虽然可能有内存浪费的问题,但每个元素只需存储数据本身,而链表的每个节点还需要额外空间来存储指向下一个节点的指针。
  • 顺序表因为数据连续存储,更利于现代计算机系统的缓存机制,可以提高访问速度。而链表由于其分散的存储,可能导致较差的缓存利用率,影响性能。
  • 11
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

poison_Program

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值