数据结构---线性表

线性表定义

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

线性表基本运算

在这里插入图片描述
增删改查

引用

参考之前我的一篇博文,指针和引用区别

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

顺序表定义

在这里插入图片描述
顺序表:用顺序存储方式实现的线性表
顺序存储。把逻辑上相邻的元素存储在物理位置上也相邻的存储单元中,元素之间的关系由存储单元的邻接关系来体现。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

顺序表java实现

顺序结构就是用数组实现的。
数组的特点:是在内存中顺序存储,因此可以很好地实现逻辑上的顺序表
在这里插入图片描述
操作无非是增、删、改、查4种情况。

插入数组元素的操作存在3种情况

  • 尾部插入
  • 中间插入
  • 超范围插入(数组扩容)

中间插入示例:
在这里插入图片描述
插入代码结构是:MyArray定义了数组类和相应的插入方法,a类是测试类

package dataStructure.myArray;

public class MyArray {
    private int[]array;
    private int size;

    public MyArray(int capacity){
        this.array = new int[capacity];
        size=0;
    }
    /**
     * 数组的中间插入(index=size就是尾插)
     * @param element 插入的元素
     * @param index    插入的位置
     */
    public void insert(int element,int index){
        if (index<0||index>size){
            throw new IndexOutOfBoundsException("插入位置超过实际范围");
        }
        //先把插入位置之后的元素后挪一位,腾出空间
        for(int i=size-1;i>=index;i--){
            array[i+1]=array[i];
        }
        //再把元素放进腾出来的空间中
        array[index]=element;
        size++;
    }
    /**
     * 输出数组元素的方法
     */
    public void  output(){
        for(int i=0;i<size;i++){
            System.out.println(array[i]);
        }
    }
}

package dataStructure.myArray;

//用于实现小灰的数组代码
public class a {
    public static void main(String[] args) {
    MyArray myArray = new MyArray(10);
    myArray.insert(3,0);
    myArray.insert(7,1);
    myArray.insert(5,2);
    myArray.insert(1,3);
    myArray.output();
    System.out.println("-----------");
    myArray.insert(6,2);
    myArray.output();

    }
}

在这里插入图片描述

代码中的成员变量size是数组实际元素的数量。
如果插入元素在数组尾部,传入的下标参数index等于size;
如果插入元素在数组中间或头部,则index小于size。
如果传入的下标参数index大于size或小于0,则认为是非法输入,会直接抛出异常。

数组扩容
数组的长度在创建时就已经确定了,此时可以创建一个新数组,长度是旧数组的2倍,再把旧数组中的元素统统复制过去,这样就实现了数组的扩容。
在这里插入图片描述

插入代码结构是:MyArray2定义了数组类和相应的插入方法,a类是测试类

package dataStructure.myArray;

public class MyArray2 {
    private int[]array;
    private int size;

    public MyArray2(int capacity){
        this.array = new int[capacity];
        size=0;
    }
    /**
     * 数组的中间插入(index=size就是尾插)
     * @param element 插入的元素
     * @param index    插入的位置
     */
    public void insert(int element,int index){
        if (index<0||index>size){
            throw new IndexOutOfBoundsException("插入位置超过实际范围");
        }
        //添加判断条件
        //判断实际元素size是否超过数组容量上限度
        if(size>=array.length){
            resize();
        }
        //先把插入位置之后的元素后挪一位,腾出空间
        for(int i=size-1;i>=index;i--){
            array[i+1]=array[i];
        }
        //再把元素放进腾出来的空间中
        array[index]=element;
        size++;
    }
    /**
     * 数组扩容方法
     */
    public void resize(){
        //每次以当前数组长度2背的增长率来扩容(创建新数组)
        int[] arrayNew = new int[array.length*2];
        //复制过去
        System.arraycopy(array,0,arrayNew,0,array.length);
        //将新数组的引用给array(array就可以控制新数组了。。。)
        array = arrayNew;

        //看看扩容后数组的长度是不是两倍关系
        System.out.println(array.length);
    }
    /**
     * 输出数组元素的方法
     */
    public void  output(){
        for(int i=0;i<size;i++){
            System.out.println(array[i]);
        }
    }
}

package dataStructure.myArray;

//用于实现小灰的数组代码
public class a {
    public static void main(String[] args) {
    MyArray2 myArray2 = new MyArray2(3);
    myArray2.insert(3,0);
    myArray2.insert(7,1);
    myArray2.insert(5,2);
    myArray2.insert(1,3);
    }
}

在这里插入图片描述

删除元素
果删除的元素位于数组中间,其后的元素都需要向前挪动1位。
在这里插入图片描述

    /**
     * 删除数组元素
     * @param index
     * @return
     * @throws Exception
     */
    public int delete(int index) throws Exception{
        if(index<0||index>=size){
            throw new IndexOutOfBoundsException("删除元素的位置超过实际范围|");
        }
        //将要删除的元素值保存
        int deletedElement = array[index];
        //挪位置
        for (int i=index;i<size-1;i++){
            array[i] = array[i+1];
        }
        //实际元素少一个,减去这个计数
        size--;
        //返回删除的元素值
        return deletedElement;
    }

数组扩容的时间复杂度是O(n),插入并移动元素的时间复杂度也是O(n),综合起来插入操作的时间复杂度是O(n)。
至于删除操作,只涉及元素的移动,时间复杂度也是O(n)。

数组所适合的是读操作多、写操作少的场景,
链表则恰恰相反

顺序表C++实现

链表定义

链表:用链式存储方式实现的线性表

单向链表

在这里插入图片描述
链表(linked list)是一种在物理上非连续、非顺序的数据结构,由若干节点(node)所组成。
单向链表的每一个节点又包含两部分,一部分是存放数据的变量data,另一部分是指向下一个节点的指针next。

对于链表的其中一个节点A,我们只能根据节点A的next指针来找到该节点的下一个节点B,再根据节点B的next指针找到下一个节点C……

双向链表

在这里插入图片描述
每一个节点除了拥有data和next指针,还拥有指向前置节点的prev指针。

内存结构图

数组在内存中的存储方式是顺序存储,那么链表在内存中的存储方式则是随机存储。
在这里插入图片描述
箭头代表链表节点的next指针

操作还是:增删查改

链表java实现


只能从头节点开始向后一个一个节点逐一查找。
在这里插入图片描述
链表中的数据只能按顺序进行访问(查找),最坏的时间复杂度是O(n)。

插入

  1. 尾部插入
  2. 头部插入
  3. 中间插入

尾插
在这里插入图片描述
头插
在这里插入图片描述
中间插
在这里插入图片描述
只要内存空间允许,能够插入链表的元素是无穷无尽的,不需要像数组那样考虑扩容的问题。

删除

  1. 尾部删除
  2. 头部删除
  3. 中间删除

尾部删除,是最简单的情况,把倒数第2个节点的next指针指向空即可。
头部删除,也很简单,把链表的头节点设为原先头节点的next指针即可。
中间删除,同样很简单,把要删除节点的前置节点的next指针,指向要删除元素的下一个节点即可。
在这里插入图片描述
Java拥有自动化的垃圾回收机制,所以我们不用刻意去释放被删除的节点,只要没有外部引用指向它们,被删除的节点会被自动回收

插入和删除操作,时间复杂度都是O(1)。
为了尾部插入的方便,代码中额外增加了指向链表尾节点的指针last。(如果没有尾指针,就得先查找到尾节点,再操作。。。)

package dataStructure.myLink;

/**
 * head,头指针
 * last,尾指针
 * size,当前链表长度
 * Node,一个节点
 */
public class MyLinklist {
    private Node head;
    private Node last;
    private int size;
    //静态内部类
    //静态内部类可以访问外部类的静态成员,不能访问外部类的普通成员。

    /**
     * data,数据域
     * next,指针域
     */
    private static class Node {
        int data;
        Node next;

        //构造方法
        Node(int data) {
            this.data = data;
        }
    }

    /**
     * 链表查找元素
     *
     * @param index 链表查找元素
     * @return
     * @throws Exception
     */
    public Node get(int index) throws Exception {
        if (index < 0 || index >= size) {
            throw new IndexOutOfBoundsException("查找超范围!");
        }
        //从头节点开始查找......
        Node temp = head;
        for (int i = 0; i < index; i++) {
            temp = temp.next;
        }
        return temp;
    }

    /**
     * 链表插入元素
     *
     * @param data  插入元素
     * @param index 插入位置
     * @throws Exception
     */
    public void insert(int data, int index) throws Exception {
        if (index < 0 || index > size) {
            throw new IndexOutOfBoundsException("插入位置超范围!");
        }
        //理论上,链表不存在扩容问题
        //建立节点
        Node insertNode = new Node(data);
        //判断当前链表状态
        if (size == 0) {
            //空链表的插入方式
            head = insertNode;
            last = insertNode;
        } else if (index == 0) {
            //链表不为空,头插法方式
            insertNode.next = head;
            head = insertNode;
        } else if (index == size) {
            //链表不为空,尾插法方式
            last.next = insertNode;
            last = insertNode;
        } else {
            //链表不为空,中间插入方式
            //先找到插入位置前一个节点
            Node preNode = get(index - 1);
            insertNode.next = preNode.next;
            preNode.next = insertNode;
        }
        //链表长度加1
        size++;
    }

    /**
     * 链表删除元素
     *
     * @param index 删除的位置
     * @return
     * @throws Exception
     */
    public Node remove(int index) throws Exception {
        if (index < 0 || index >= size) {
            throw new IndexOutOfBoundsException("删除位置超出链表节点范围");
        }
        //删除节点的引用
        Node removeNode = null;
        if (index == 0) {
            //删除头节点
            removeNode = head;
            head = head.next;
        } else if (index == size - 1) {
            //删除尾节点
            //获取尾节点前一个节点
            Node prevNode = get(index - 1);
            //保存删除的尾节点地址,并将前一个节点指针域置空
            removeNode = prevNode.next;
            prevNode.next = null;
            //移动尾指针
            last = prevNode;
        } else {
            //删除中间节点
            Node preNode = get(index - 1);
            Node nextNode = preNode.next.next;
            removeNode = preNode.next;
            //将删除位置前一个节点的指针域指向删除位置后面的节点(完成删除)
            preNode.next = nextNode;
        }
        size--;
        return removeNode;
    }

    /**
     * 输出链表
     * 从头开始遍历
     */
    public void output(){
        Node temp = head;
        while (temp!=null){
            System.out.println(temp.data);
            //指针后移
            temp = temp.next;
        }
    }

}

链表C++实现

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值