线性表(链表实现和数组实现)(数据结构一)

1 . Concept概念

Question

数据结构一二三四

集合

Collaction接口
Map接口 

集合类:本质就是一个数据容器,盒子。同属于一个集合。

线性表:一对一
树:一对多
图:多对多

逻辑结构
物理结构:数组 / 链表

为什么需要集合类?

	存储更多类型问题,扩容问题,内存空间浪费问题

	数组不方便:手动修改代码

	盒子,透明,屏蔽底层

数据结构(一)线性表

线性表是一种逻辑结构。
线性表是指:n个元素的有序序列,除表头元素和表尾元素外,其他元素都有唯一前驱和唯一后继。

线性表是逻辑结构,顺序表和链表是物理结构(存储结构)
在这里插入图片描述

我是红色

时空复杂度(分析)

时间复杂度&空间复杂度
HashMap O(1)


2 . 线性表(Array && Linked List)(数组&链表)

2.0 Array(数组)&& Linked List(链表)

在这里插入图片描述
注:以上结构适用于考研,实际中,首结点就是头结点

在这里插入图片描述

链表的分类

循环链表:单链表的增强,让尾结点的下一个指针域指向头结点
双向链表:单链表的增强,让每一个结点再维护一个向前的指向,指向前一个结点
双向循环链表:双向链表的一个增强,尾结点的后指针指向首结点,首结点的前指针指向尾结点。

单链表:简单的形式,next指针
循环链表:单链表的增强,尾结点指向头结点
双向链表:前指针 + 后指针
双向循环链表:双向链表的增强,尾结点的后指针指向首结点,首结点的前指针指向尾结点。

2.1 单链表来实现一个线性表(3月3日)

MyLinked

	private Node head; // 链表的头结点
    private int size; // 这个链表存储了多少元素

	@Override
    public String toString() {
    
    
        return "MyLinked{" + head +
                '}';
    }


	class Node {
    
    
        String value;
        Node next;

        public Node(String value, Node next) {
    
    
            this.value = value;
            this.next = next;
        }

        @Override
        public String toString() {
    
    
            return "{" +
                    "v='" + value + '\'' +
                    ", n=" + next +
                    '}';
        }
    }

2.2 双向链表来实现一个线性表(3月3日)

MyDBLinked

	private Node head; // 链表的头结点
    private Node end; // 尾结点
    private int size; // 这个链表存储了多少元素

	@Override
    public String toString() {
    
    
        return "MyLinked{" + head +
                '}';
    }
	
	class Node {
    
    
        Node pre;
        String value;
        Node next;

        public Node(Node pre, String value, Node next) {
    
    
            this.pre = pre;
            this.value = value;
            this.next = next;
        }
        
        //请教了老师
        @Override
        public String toString() {
    
    
            String preValue = null;
            if (pre != null) preValue = pre.value;
            return "{" +
                    "p='" + preValue +
                    "\tv='" + value + '\'' +
                    ", n=" + next +
                    '}';
        }
    }

用链表实现线性表需要实现的API
用数组实现线性表需要实现的API

多写几遍,提高思维能力和熟练度!
多写几遍,提高思维能力和熟练度!
多写几遍,提高思维能力和熟练度!
添加 public boolean add(String str)      public boolean add(int index, String str)
删除 public boolean remove(String str)   public String remove(int index)
查找 public boolean contains(String str) public String get(int index)
替换 public boolean set(String oldValue, String newValue)    public String set(int index, String newValue)

重要
注:线性表是逻辑结构。单链表(非循环)和双链表(非循环)实现线性表是指物理上采用链式存储结构去实现。
注:toString()方法的重写(理解:引用类型不重写就是调用Object的toString()方法,打印地址)

注:以上两种为链式存储,下面为顺序存储

2.3 数组来实现一个线性表(3月4日)

如果使用数组来实现一个集合类:一般伴随着: 数组初始化, 数组扩容

MyList <T>		泛型


	private final  int MAX_CAPACITY = Integer.MAX_VALUE - 8;// 最大阈值
    private Object[] arrs;// 底层数组
    private int size; // 这个链表存储了多少元素

    
    public MyList() {
    
    
        this.arrs = new Object[10];
    }
	
	如果使用数组来实现一个集合类:一般伴随着: 数组初始化, 数组扩容
	
    初始化
    public MyList(int initCapacity) {
    
    
        if (initCapacity <= 0 || initCapacity > MAX_CAPACITY)
        	throw  new IllegalArgumentException("initCapacity = " + initCapacity);
        this.arrs = new Object[initCapacity];
    }
    
    扩容
	private void grow(int newLen) {
    
    
        Object[] objects = new Object[newLen];// 创建一个新数组
        // 把旧数组的数据转移到新数组
        for (int i = 0; i < arrs.length; i++) {
    
    
            objects[i] = arrs[i];
        }
        arrs = objects;// 把新数组赋值给arr
    }

	private int getLen() {
    
    
        // 获取一个新的扩容长度
        int oldLen = arrs.length;
        int newLen = oldLen << 1;// 新长度是旧长度的两倍(右移1位)

        if (newLen < 0 || newLen > MAX_CAPACITY) newLen = MAX_CAPACITY;
        if (oldLen == newLen) throw new RuntimeException("arr is max");

        return newLen;
    }
这里是空白分隔



这里是空白分隔



这里是空白分隔
单链表的操作

增加

在这里插入代码片

删除

temp.next = temp.next.next;

查找

按值
按索引

在这里插入图片描述

3.用数组实现一个线性表

4.interview question(面试题)

单链表的常见面试题有如下:

1、求单链表中有效节点的个数
**分析:**有效结点

在这里插入代码片

2、查找单链表中的倒数第K个结点(新浪)

在这里插入代码片

3、单链表的反转(腾讯,有点难度)

在这里插入代码片

4、从尾到头打印单链表(百度,要求方式1:反向遍历。方式2:Stack栈)

在这里插入代码片

5、合并两个有序的单链表,合并之后的链表依然有序(练习)

在这里插入代码片

刷算法最重要的不是解决,而是一题做半年,想到更优秀的方式去实现!!!

王道练习1
在这里插入图片描述

添加
带头结点(知道就行)、不带头结点(java中习惯)

判断是否为空:
size == 0 或者 head == null都可以
if(size==0){

}

执行到这一步,意味着:原链表不空
找到尾部元素,把这个元素添加上去

mid.next == null的时候,mid是原尾结点,那么只需要把新结点加到旧结点的尾部

DemoMyLinked1
不关心如何存,只希望放元素

重写toString()好看

删除
if(size == 0) throw new RuntimeException
判断链表是否空(是就抛出异常,因为false一般找不到时返回)

判断删除的是否是头结点:是的话,头结点后移一个就可以

在这里插入图片描述

在这里插入图片描述

删除的不是头结点
向后移动查找位置:直到

两种结果:
1,没有要删除的元素
2,mid.next就是要找的元素

==============

快指针 = 2 * 慢指针
2(x+m) = x + ny + m

反序链表

(逻辑,数学)
TODO:看一下(空指针问题)
查找:
修改
链表的添加:根据下标去添加

练习:
根据下标查找一个值
根据下标替换一个值

双向链表:维护首结点和尾结点
插入到尾结点
根据下标添加
根据内容删除元素
在这里插入图片描述

在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/AC_872767407/article/details/114281843