讲一讲线性表

 线性表更确切的说是一种逻辑概念名称,指的是每个元素 有且尽有一个前驱和一个后继节点,所有的元素组成一个线性表.

而他在物理上有两种存储方式,一种是顺序存储,一种是链式存储

顺序存储指的就是存放在内存连续的空间,我们有现成的数组可供存放

这种存储方式的优点就是读取快,众所周知,数组的读取元素的时间复杂度是O(1),那你知道为什么是O(1)吗,你会说有索引,你能说的再详细一点吗。

我这里顺带解释 一下O(1)的原因,从底层结构看索引位置的操作,其实是每个数组都持有头指针,也就是数组元素的第一个位置的地址,而又由于数组元素的数据类型都是相同的,

那么就是每个元素占的存储空间都是一样的,而且地址是连续的,所以我们找第n个元素的位置只需要头指针+(n-1)*数据类型的大小就可以定位到第n个元素的位置了,而这个操作是一次计算就可以了,所以时间复杂度是O(1)

这种存储方式的缺点是插入删除慢,中间插入的时候,需要先将插入位置后面的元素从后到前依次向后移动一个位置,平均计算出来的时间复杂度是O(n)

删除也一样,需要把删除位置从前往后依次向前移动一个位置,平均时间复杂度也是O(n)

链式存储指的是每一个元素不仅存储自己的数据,而且存储指向下个元素的指针,这使得存放空间随意,而不用考虑每次要开辟足够的空间来存放线性表.

链式存储的优点是插入删除快,时间复杂度是O(1)

这里有必要说一下插入删除的标准动作:

插入

//s是新节点,p是插入位置的前一个节点
s->next=p->next;
p->next=s;

就是将前一个 节点原本指向的后继节点赋值给新节点指向后继节点的指针

然后再讲前一个节点的后继节点指针改为新节点的地址。

删除 

p->next=p->next->next;

就是将p的后继节点的指针指向p的后继节点的后继节点,相当于越过了中间那个节点。达到删除的目的

这里也顺便提一下头插法和尾插法,

顾名思义,头插法就是将新结点插入到链表的头,

尾插法就是将新结点插入到链表的尾端

链式存储的缺点就是查找慢咯,每次都得从头结点开始依次向下查找.时间复杂度是O(n)

以上说的是单链表的情况。

另外还有循环链表,就是尾结点指向头结点

双向链表,就是每个节点还有指向前一个节点的指针。

顺序存储和链式存储是物理上的概念

基于这两个概念,我们从逻辑上又定义了栈和队列,

因此,栈可以用顺序存储的方式来实现,也就是数组方式来实现,

public class ArrayStack {
    private int[] nums;
    private int count;

    public ArrayStack(int n){
        nums = new int[n];
        count = 0;
    }

    public boolean push(int num){
        if(count>=nums.length){
            return false;
        }
        nums[count] = num;
        count++;
        return true;
    }

    public int pop(){
        if (count ==0 ) {
            return 0;

        }
        int res = nums[count-1];
        count --;
        return res;
    }
}

也可以用链式存储来实现,也就是链表的方式来实现.

public class LinkedStack {
    private int size;
    private Node head;

    public LinkedStack(){
        this.size = 0;
        this.head = null;
    }

    public boolean push(Node node){
        if(size == 0){
            head = node;
        }else{
            node.next = head;
            head =node;

        }
        size++;
        return true;
    }

    public Node pop(){
        if(size == 0){
            return null;
        }
        Node oldHead = head;
        head = head.next;
        size --;
        return oldHead;
    }
}

队列也一样.

队列的数组实现

public class ArrayQueue {

    private int head;
    private int tail;
    private int[] nums;

    public  ArrayQueue(int n){
        nums =new int[n];
        head = 0;
        tail = 0;
    }

    public boolean push(int n){
        if(tail == nums.length){
            return false;
        }

        nums[tail] = n;
        tail++;
        return true;
    }

    public int pop(){
        if(head == tail){
            return 0;
        }
        int res = nums[head];
        head ++;
        return res;
    }

}

队列的链表实现

public class LinkedQueue {
    private Node head;
    private Node tail;
    private int size;

    public LinkedQueue(){
        head = null;
        tail = null;
        size =0 ;

    }

    public boolean enqueue(Node node){
        if(tail == null){
            head =node;
            tail = node;
        }else{
            tail.next = node;
            tail = node;
        }

        return true;

    }

    public Node dequeue(){
        if(head == null){
            return null;
        }

        Node oldHead =  head;
        head = head.next;
        oldHead.next = null;

        return oldHead;
    }
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值