数据结构与算法学习笔记(一)

数据结构与算法是有一定难度的,大家学习的时候要多练,一时不懂没关系要多多练习,越练越能明白其中的意义;

数据结构

1,逻辑结构

这方面我先讲概念,后面会有例子给大家深入了解

逻辑结构分为:
线性结构:线性表,栈,队列,串
非线性就结构:树,图

存储结构分为:
顺序存储结构:连续依次存储的单元存储元素,数据元素之间的存储关系来表示关系
链表存储结构:
用一组任意存储的单元存储元素,数据元素之间的逻辑关系用指针来表示
索引存储结构:

  • 在存储信息的时候,建立一个附加的索引表
  • 索引表每一页为一个索引项,也就是地址,能通过关键字来标识结点的数据
  • 稠密索引:每个结点都有一个索引项在表中关联
  • 稀疏索引:一个表只有一个索引关联
    散列存储:根据结点的关键字直接计算出该结点的存储地址

数据类型:

  • 以java为例子
    基本数据类型就是byte,short,int,long,float,double,char,boolean等,
    构造数据类型就是数组,集合,枚举等;
    空类型void,跟c语言比差了指针,结构,共用体;
    基本的数据类型可以实现数组,集合字符等,但是不能表示栈,队列,树,图等;

  • 数据类型:就的一组性质相同的值的集合以及定义这个集合的一组值的总称;
    作用就是约束变量或者常量的取值范围,约束变量或者常量的操作

2.算法

算法所耗费的时间:该算法每条语句的频度之和。

1. 时间复杂度:

只比较函数之间的数量级,如函数a=5n^2,而函数b=10n;那么假设那无穷大时,函数的增长率是相同的,所以a函数比较复杂;

求算方法:有个关于时间复杂度的多项式,不考虑低次幂和高次项的系数,只考虑贡献最大的项式的高次幂;
伪代码:

int a = 0;
        for(int i=1;i<n;i++){//循环n次最后判断一次是否符合循环条件+1次所以运行了n+1次
            for (int j=(i+1);j<n;j++){//外层执行n次,内层执行n-1次判断循环条件加一次为n次;这里执行n*(n)次
              a++;
            }
        }

2.空间复杂度:

将算法存储所需要的空间表示为关于n的函数;比如:数组a中有n个逆序存储到原数组
伪代码:


	for(int i=0;i<n/2;i++){
	temp = a[i];
	//将数组a数组的开头和结尾互换中间也一次互换需要换n/2次,只需要一个temp作为中间的存在空间顾空间复杂度为1
	a[i] = a[n-i-1];
	a[n-i-1] = temp
}

伪代码:


	for(int i=0;i<n;i++){
	temp[i] = a[n-i-1];
	//将数组a从末尾往头依次取出元素,依次放到temp数组的头到尾;一样也完成数组的逆序存储,只不过是空间上必须要有一个跟数组a一样的空间的数组temp所以空间复杂度为n;
	for(int i=0;i<n;i++){
	a[i] = temp[i];
}
}

3.稀疏数组:

将二维数组中无用的数据压缩,成一个3列n行的的数组;
下标 行 列 值
[0] 原数组几行 原数组几列 有用的值有几个
[1]
[2]
[3]
[4]
[5]
[1] - [5]是数组下标,中间区域记录的是具体数据的所在的行,所在的列,具体数据

//新建一个二维数组
        int[][] chessArr = new int[11][11];
        chessArr[1][2] = 11;
        chessArr[3][5] = 23;
        chessArr[4][8] = 45;
        //输出二维数组
        System.out.println("这是一个二维数组:");
        for (int[] row : chessArr){
            for (int data : row){
                System.out.printf("%d\t",data);
            }
            System.out.println();
        }

        //遍历数组取出有用的数据;
        int sum = 0;
        for (int i = 0;i < chessArr.length;i++) {
            for (int j = 0;j< chessArr.length;j++) {
                if (chessArr[i][j]!=0) {
                    sum++;
                }
            }
        }
        System.out.println("sum 值:"+sum);
        //定义一个稀疏数组来存放这些数据
        int [][] sparseArr = new int[sum+1][3];
        sparseArr[0][0] = 11;
        sparseArr[0][1] = 11;
        sparseArr[0][2] = sum;

        int count = 0;
        //因为需要用chessArr的i和j所以要对原来的数组遍历取出数据
        for (int i = 1;i<11;i++) {
            for (int j = 1;j<11;j++) {
                if (chessArr[i][j]!=0) {
                    //因为稀疏数组的第一行是记录原数组的大小和有用数据的多少
                    //在前面定义过了所以使用一个计数器count来表示从第一行以外的数据进行装配
                    count++;
                    sparseArr[count][0] = i;
                    sparseArr[count][1] = j;
                    sparseArr[count][2] = chessArr[i][j];
                }
            }
        }

        //输出稀疏数组
        for (int[] row : sparseArr){
            for (int data : row){
                System.out.printf("%d\t",data);
            }
            System.out.println();
        }
        //将稀疏数组转为二维数组
        int[][] chessArr2 = new int[sparseArr[0][0]][sparseArr[0][1]];


        //提取稀疏数组中的数据并装配到这个二维数组中
        for (int i = 1;i<sparseArr.length;i++){
            //从第二行开始遍历,如果从第行开始遍历会越界;因为前面定义数组就决定了长度
            chessArr2[sparseArr[i][0]][sparseArr[i][1]] = sparseArr[i][2];
        }
        //遍历二维数组输出与最开始的二维数组看下有没有差异
        System.out.println();
        for (int[] row :chessArr2){
            for (int data : row){
                System.out.printf("%d\t",data);
            }
            System.out.println();
        }

在这里插入图片描述

4.队列

  • 什么是队列;是一种先入先出的数据结构;
  • 头部指针first指向队列头部的前一个数据,尾部指针last指向队列的尾部(最后一个数据);
  • 添加数据的时候影响尾指针,而取出数据的时候影响的是front指针

1. 数组模拟队列思路分析:

  • 首先要创建一个队列,队列里面必须要有3个属性头指针,尾指针,最大容量;因为是数组模拟所以还要有个数组来存放数据。
  • 创建完了,要有判断队列什么时候为空,什么时候满,不然没办法往里面添加数据和去数据
  • 队列为空时,队列front和rear都为-1,那么我们可以推出当队列front==rear时队列为空
  • 队列为满,添加一个数据满了,rear当尾指针指向最大容量时队列就满了那么rear==MaxSize-1
  • 往队列中添加数据,添加影响尾指针,头部不影响,那么忽略头部,添加一个元素队列rear+1,向后移动,这时候有个问题,数组是不能动态扩容,所以要么重写ArrayList实现动态数组,要么实现环形队列这个以后会发后续的博客,到时候再讲,先给大家一个概念。
  • 从队列取数据,影响的是尾部指针,取一个数据时,front+1
    在这里插入图片描述

2.具体实现代码

public static void main(String[] args) {
        //测试
        //创建一个队列
        ArrayQueue queue = new ArrayQueue(3);
        char key = ' ';
        //接受用户输入
        Scanner scanner = new Scanner(System.in);
        boolean loop = true;
        while (loop){
            System.out.println("s(show):显示队列");
            System.out.println("e(exit):退出程序");
            System.out.println("a(add):添加数据到队列");
            System.out.println("g(get):从队列取数据");
            System.out.println("h(head):查看队列头部");
            key = scanner.next().charAt(0);
            //接受一个字符
            switch (key){
                case 's' :
                    queue.showQueue();
                    break;
                case 'a' :
                    System.out.println("输出一个数");
                    int value = scanner.nextInt();
                    queue.addQueue(value);
                    break;
                case 'g' :
                    try {
                        int res = queue.getQueue();
                        System.out.printf("取出数据%d\n",res);
                    }catch (Exception e){
                        System.out.println(e.getMessage());
                    }
                    break;
                case 'h' :
                    try {
                        int res = queue.headQueue();
                        System.out.printf("取出数据%d\n",res);
                    }catch (Exception e){
                        System.out.println(e.getMessage());
                    }
                    break;
                case 'e' :
                    scanner.close();
                    loop = false;
                    break;
                default:
                    break;
            }
        }
        System.out.println("程序退出");
    }
}
class ArrayQueue{
//创建队列需要的属性
    private int maxSize;
    private int front;
    private int rear;
    private int[] arr;

    //创建队列的构造器(初始化时就能直接生效)
    public  ArrayQueue(int arrMaxSize){
    //这里是用临时变量的方式传递值,你们也可以用this
        maxSize = arrMaxSize;
        arr = new int[maxSize];
        //用来存放数据
        front = -1;
        //指向队列头的前一个位置
        rear = -1;
        //指向队列尾部(最后一个数据)
    }

    //判断队列已满
    public  boolean isFull(){
        return rear == maxSize-1;
    }
    //判断队列为空
    public boolean isEmpty(){
        return rear == front;
    }
    //添加数据到队列
    public void addQueue(int n){
        if (isFull()){
            System.out.println("队列已经满了,不能添加数据");
            return;
        }
        rear++;
        arr[rear] = n;
    }
    //获取队列数据(出队列)
    public int getQueue(){
        if (isEmpty()){
            //通过异常来返回信息
            throw new RuntimeException("队列为空不能去数据");
            //这里要注意不加return,因为throw本身会马上返回,导致代码return
        }
        front++;
        return arr[front];
    }

    //显示队列所有数据
    public void  showQueue(){
        if (isEmpty()){
            System.out.println("队列空的,没有数据");
            return;
        }
        for (int i = 0; i < arr.length; i++){
            System.out.printf("arr[%d]=%d\n",i,arr[i]);
        }
    }
    public int headQueue(){
        if (isEmpty()){
            throw new RuntimeException("队列空的,没有数据");
        }
        return arr[front+1];
        //因为front指向的是队列头的前一个数据
    }
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值