数据结构-线性表-深入浅出

线性表

  1. 数组

    1. 概念:数组(Array)是有限个相同类型的变量所组成的有序集合,数组中的每一个变量被称为元素。数组下标从零开始。数组用一组连续的内存空间来存储一组具有相同类型的数据
    2. 时间复杂度:读取和更新都是随机访问,所以是O(1)。插入并移动元素的时间复杂度也是O(n)。删除操作,只涉及元素的移动,时间复杂度也是O(n)
    3. 优点:数组拥有非常高效的随机访问能力,只要给出下标,就可以用常量时间找到对应元素
    4. 缺点: 插入和删除元素方面。由于数组元素连续紧密地存储在内存中,插入、删除元素都会导致大量元素被迫移动,影响效率。申请的空间必须是连续的,也就是说即使有空间也可能因为没有足够的连续空间而创建失败
    5. 应用:ArrayList
    6. 插入删除查找-代码
  2. 链表

    1. 概念:链表(linked list)是一种在物理上非连续非顺序的数据结构,由若干节点(node)所组成。每个结点包括两个部分:一个是存储数据元素的数据域,另一个是存储下一个结点地址的指针域
    2. 单链表:单向链表的每一个节点又包含两部分,一部分是存放数据的变量data,另一部分是指向下一个节点的指针next
    3. 双向链表:双向链表的每一个节点除了拥有data和next指针,还拥有指向前置节点的prev指针。
    4. 循环链表:链表的尾节点指向头节点形成一个环,称为循环链表
    5. 存储原理:链表的每一个节点分布在内存的不同位置,依靠next指针关联起来。这样可以灵活有效地利用零散的碎片空间。
    6. 查找节点,更新节点,插入节点,尾部插入,头部插入,中间插入,尾部删除,头部删除,中间删除
    7. 时间复杂度:查找节点 : O(n),插入节点:O(1),更新节点:O(1),删除节点:O(1)
    8. 优势:插入、删除、更新效率高,省空间
    9. 劣势:查询效率较低,不能随机访问
    10. 应用:链表的应用也非常广泛,比如树、图、Redis的列表、LRU算法实现、消息队列等
    1. 概念:栈(stack)是一种线性数据结构,栈中的元素只能先入后出(First In Last Out,简称FILO)。
      最早进入的元素存放的位置叫作栈底(bottom),最后进入的元素存放的位置叫作栈顶 (top)
    2. 时间复杂度:入栈和出栈的时间复杂度都是O(1)
    3. 应用:函数的调用,浏览器前进和后退
    4. 数组和链表实现栈
/**
* 数组实现
*/
public class ArrayStack {
private int[] nums; // 数组
private int count; // 栈中元素个数
// 初始化数组,申请一个大小为n的数组空间
public ArrayStack(int n) {
this.nums = new int[n];
this.count = 0;
}
// 入栈操作
public boolean push(int n) {
// 数组空间不够了,直接返回false,入栈失败。 没有扩容
// nums.len*2 arraycopy
if (count >= nums.length) return false;
// 将item放到下标为count的位置,并且count加一
nums[count] = n;
count++;
return true;
}
// 出栈操作
public int pop() {
// 栈为空,则直接返回0
if (count == 0) return 0;
// 返回下标为count-1的数组元素,并且栈中元素个数count减一
int n = nums[count-1];
count--;
链表实现
return n;
}
public static void main(String[] args) {
ArrayStack as=new ArrayStack(8);
as.push(3);
as.push(5);
as.push(1);
as.push(4);
System.out.println(as.pop());
System.out.println(as.pop());
System.out.println(as.pop());
System.out.println(as.pop());
}
}

/**
* 链表节点
*/
public class Node {
int value;
Node next;
public Node(int value) {
this.value = value;
}
}
/**
* 链表实现
*/
public class LinedStack {
int size;
Node head; //头节点
/**
* 初始化
*/
public LinedStack() {
head = null;
size = 0;
}
/**
时间复杂度
* 入栈
*
* @param node
*/
public void push(Node node) {
//head
if (size == 0) {
head = node;
}
//非head
else {
node.next = head;
head = node;
}
size++;
}
/**
* 出栈
*
* @return Node
*/
public Node pop() {
if (size > 0) {
Node oldHead = head;
head = head.next;
size--;
return oldHead;
} else {
return null;
}
}
public static void main(String[] args) {
Node n1=new Node(3);
Node n2=new Node(5);
Node n3=new Node(1);
Node n4=new Node(4);
LinedStack ls=new LinedStack();
ls.push(n1);
ls.push(n2);
ls.push(n3);
ls.push(n4);
System.out.println(ls.pop().value);
System.out.println(ls.pop().value);
System.out.println(ls.pop().value);
System.out.println(ls.pop().value);
}
}
  1. 队列
    1. 概念:队列(queue)是一种线性数据结构,队列中的元素只能先入先出(First In First Out,简称 FIFO)。队列的出口端叫作队头(front),队列的入口端叫作队尾(rear)。
    2. 时间复杂度:入队和出队都是O(1)
    3. 代码实现
/**
* 用数组实现的队列
*/
public class ArrayQueue {
// 数组:items,数组大小:n
int[] nums;
// head表示队头下标,tail表示队尾下标
int head = 0;
int tail = 0;
// 申请一个大小为capacity的数组
public ArrayQueue(int size) {
nums = new int[size];
}
// 入队
public boolean enqueue(int n) {
链表实现
// 如果tail == n 表示队列已经满了
if (tail == nums.length) return false;
nums[tail] = n;
++tail;
return true;
}
// 出队
public int dequeue() {
// 如果head == tail 表示队列为空
if (head == tail) return 0;
int ret = nums[head];
++head;
return ret;
}
public static void main(String[] args) {
ArrayQueue aq=new ArrayQueue(8);
aq.enqueue(3);
aq.enqueue(5);
aq.enqueue(1);
aq.enqueue(4);
System.out.println(aq.dequeue());
System.out.println(aq.dequeue());
System.out.println(aq.dequeue());
System.out.println(aq.dequeue());
}
}

import com.lagou.line.queue.Node;
/**
* 链表实现
*/
public class LinkedQueue {
Node head;
Node tail;
int size;
public void enqueue(Node node){
if (tail == null){
head = node;
tail=node;
}else {
tail.next = node;
tail = node;
}
size++;
时间复杂度
入队和出队都是O(1)
应用
资源池、消息队列、命令队列等等
第2节 散列表
概念
散列表也叫作哈希表(hash table),这种数据结构提供了键(Key)和值(Value)的映射关系。只要
给出一个Key,就可以高效查找到它所匹配的Value,时间复杂度接近于O(1)}
public Node dequeue (){
if (head == null) return null;
Node h = head;
//将拉取的节点的下一个节点变成新的表头
head = head.next;
//把旧的表头的下一个节点指向设置为null,让gc回收
h.next = null;
//队列为空
if (head == null)
tail = null;
size--;
return h;
}
public static void main(String[] args) {
Node n1=new Node(3);
Node n2=new Node(5);
Node n3=new Node(1);
Node n4=new Node(4);
LinkedQueue lq=new LinkedQueue();
lq.enqueue(n1);
lq.enqueue(n2);
lq.enqueue(n3);
lq.enqueue(n4);
System.out.println(lq.dequeue().value);
System.out.println(lq.dequeue().value);
System.out.println(lq.dequeue().value);
System.out.println(lq.dequeue().value);
}
}

  1. 散列表
    1. 概念:散列表也叫作哈希表(hash table),这种数据结构提供了键(Key)和值(Value)的映射关系。只要给出一个Key,就可以高效查找到它所匹配的Value,时间复杂度接近于O(1)。
    2. 存储原理:散列表在本质上也是一个数组。散列表的Key则是以字符串类型为主的。通过hash函数把Key和数组下标进行转换。作用是把任意长度的输入通过散列算法转换成固定类型、固定长度的散列值
    3. Hash冲突(碰撞):由于数组的长度是有限的,当插入的Entry越来越多时,不同的Key通过哈希函数获得的下标有可能是相同的,这种情况,就叫作哈希冲突。
    4. 开放寻址法:开放寻址法的原理是当一个Key通过哈希函数获得对应的数组下标已被占用时,就寻找下一个空档
      位置
    5. 链表法:数组的每一个元素不仅是一个Entry对象,还是一个链表的头节点。每一个Entry对象通过next指针指向它的下一个Entry节点。当新来的Entry映射到与之冲突的数组位置时,只需要插入到对应的链表中即可,默认next指向null
    6. 应用:HashMap,布隆过滤器。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值