线性表更确切的说是一种逻辑概念名称,指的是每个元素 有且尽有一个前驱和一个后继节点,所有的元素组成一个线性表.
而他在物理上有两种存储方式,一种是顺序存储,一种是链式存储
顺序存储指的就是存放在内存连续的空间,我们有现成的数组可供存放
这种存储方式的优点就是读取快,众所周知,数组的读取元素的时间复杂度是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;
}
}