顺序表和链表之间的对比(含代码)

顺序表

  • 数据保存在连续的内存空间上
  • 支持随机访问
  • 擅长尾插和尾删(O(1),如若触发扩容逻辑 - > O(N)
  • 不擅长中间位置插入/删除 O(N) ,效率低
public class SeqList {
    private int[] datas = new int[100]; //一个叫datas的内存有 100 的空间
    private int size = 0;  //把存在datas里的叫size,期初是空的 ,所以 = 0

    public int getSize() {
        return size; 
        //这里的size只能get,不能set,因为size是通过之后顺序表的增删来修改的,所以这里不能乱动
        //这个getSize的原因就是:上面的size是private,而下面这个代码(display)我要使用它,
        // 因为它是私有的所以我不能直接使用它,所以得用get这个方法
    }

    public void display() {
        //打印顺序表
        //依次打印出来,打印就相当于数组里的数组转为字符串
        //形如:[1,2,3,4,5]
        String ret = "[";
        for (int i = 0; i < size; i++) {
            ret += datas[i];
            if(i < size - 1){
                ret += ",";
            }
        }
        ret += "]";
        System.out.println(ret);
    }
    //这个方法呢就是为了我之后写的这些方法写好之后,我要对他进行测试看他O不OK,方便把数组打印出来


    //在pos位置add data(此data,不是内存datas)
    //pos是我要插入的这个数的位置,也就是下标;
    //data是插入的这个数的值
    public void add(int pos, int data) {
        //首先要关注pos的有效性
        if(pos < 0 || pos > size){
            return;
        }

		//这个时候就需要扩容了
        if(size >= datas.length){  
            int[] newDatas = new int[datas.length * 2];   
            //一般扩容都是在原基础上 * 2
            for (int i = 0; i < datas.length ; i++) {
                newDatas[i] = datas[i];
            }
            datas = newDatas;     
            //扩容后任然叫回原来的名字
        }
        
        //现在开始正式的add
        //1.尾插的情况
        if(pos == size){
            datas[pos] = data;
            size++;
            return;
        }
        //2.普通位置的插入
        //插入到pos后,pos后的数据依次向后移
        for (int i = size - 1;i >= pos;i--) {  
        //注意此处for循环的内部,顺序表的后移,是从最后一个数开始的,记得画图
            datas[i + 1] = datas[i];
        }
        datas[pos] = data;
        size++;
    }
    public boolean contains(int toFind) {
        // 循环访问每个元素并进行比较.
        // 如果发现某个元素和 toFind 相等, 就找到了, 返回 true
        // 如果所有元素都找完了, 也没找到相等的, 就返回 false
        for (int i = 0; i < size; i++) {
            if (datas[i] == toFind) {
                return true;
            }
        }
        return false;
    }

    public int search(int toFind) {  //某个元素的下标
        for (int i = 0; i < size; i++) {
            if(datas[i] == toFind){
                return i;
            }
        }
        return -1;
    }

    public int getPos(int pos) {  //某下标下的数的值
        return datas[pos];
    }


    public void setPos(int pos, int value) {   
    //给某下标的值赋一个值
        datas[pos] = value;
    }

    public void remove(int toRemove) {   
    //删除第一次出现的值(也就是toRemove)
        int pos = search(toRemove);   //先找到要删的这个值的下标
        if(pos == -1) {    //也就是没找到,这点要是看不明白就返回search方法看
            return;
        }

        if(pos == size - 1){   //删尾
            size--;
            return;
        }

        //普通删去
        for(int i = pos;i < size - 1; i++) {  //从要删的那个的后一个开始一个一个往前移
            datas[i] = datas[i + 1];
        }
        size--;
    }

    public void clear() {
        size = 0;
    }


}

链表

  • 元素之间不是在连续的内存空间上,给每个数据节点引入了一个next引用,通过这个引用就能找到当前节点的下一个节点
  • 不支持随机访问
  • 擅长中间插入元素/删除元素 O(1),效率高
  • 存储相同数量的数据时,链表占用的内存空间比顺序表大(因为链表的每个节点还得维护一个next)
//一个节点
class Node {
    public int data;  //数据
    public Node next = null; //下一个节点的位置

    public Node(int data) {
        this.data = data;
    }
}

public class LinkedList {
    private Node head = null;  //头节点,初始为null,且这个链表没有傀儡节点

    public void display() {
        for(Node cur = head; cur != null; cur = cur.next) {
            System.out.print(cur.data + " ");
        }
        System.out.println();
    }

    public void addFirst(int data) {
        //头插法
        //1.根据data值,构建一个链表的节点(Node对象)
        //2.如果他是个空链表
        //3.不是空链表
        
        //1.
        Node node = new Node(data);
        //2.
        if (head == null) {
            head = node;
            return;
        }
        //3.
        node.next = head;
        head = node;
    }

    public void addLast(int data) {
        //尾插法
        Node node = new Node(data);
        if(head == null) {
            head = node;
            return;
        }
        //不是空链表的时候,先找出最后一个节点
        Node tail = head;
        while(tail.next != null) {
            tail = tail.next;
        }//循环结束就是最后一个节点
        tail.next = node;
        node.next = null;
    }
    private int getSize() {
        int size = 0;
        for (Node cur = head; cur != null; cur = cur.next){
            size++;
        }
        return size;
    }

    public boolean addIndex(int index,int data) {
        //index相当于顺序表里的pos,
        //index就相当于下标
        //1.先判断index的有效性
        int size = getSize();
        if (index < 0 || index > size) {
            return false;
        }
        if (index == 0) {
            addFirst(data);
            return true;
        }
        if (index == size) {
            addLast(data);
            return true;
        }
        Node node = new Node(data);
        Node prev = getPos(index - 1);
        node.next = prev.next;
        prev.next = node; //这个地方顺序不能错了
        return true;

    }
    private Node getPos(int index) {//给定下标index,找到节点
        Node cur = head;
        for (int i = 0; i < index; i++) {
            cur = cur.next;//这步操作的提前必须得保证cur是非null
        }
        return cur;
    }
     public boolean contain(int key) {
        for (Node cur = head; cur != null;cur = cur.next) {
            if (cur.data == key) {
                return true;
            }
        }
        return false;
     }

     public void remove(int key) {
        //1.头节点
         if (head.data == key) {
             head = head.next;
             return;
         }
         //2.不是头节点,那就得找到该节点的前一个节点
         Node prev = searchPrev(key);
         Node toDelete = prev.next;
         prev.next = toDelete.next;
     }

     private Node searchPrev(int key) {//找key前一个节点
        for (Node cur = head; cur != null
                && cur.next != null;cur = cur.next) {
            if (cur.next.data == key) {
                return cur;
            }
        }
        return null;
     }

     public void removeAll(int key) {
        //1.先删除非头节点情况,需要找到key的前一个节点
         //2.删除是头节点的情况
         //1.
         Node prev = head;
         Node cur = head.next;
         while (cur != null) {
             if (cur.data == key) {
                 prev.next = cur.next;
                 cur = prev.next;
             }else {
                 //prev和cur同时往后移
                 prev = cur;
                 cur = cur.next;
             }
         }
         //2.头结点情况
         if (head.data == key) {
             head = head.next;
         }
     }

     public void clear() {
        head = null;
     }
}


原创文章 11 获赞 6 访问量 304

猜你喜欢

转载自blog.csdn.net/weixin_45122262/article/details/105381856