java数据结构与算法(线性,非线性结构,稀疏数组,队列,链表)

  1. 线性结构
  2. 非线性结构
  3. 稀疏sparsearray数组
  4. 队列
  5. 环形队列
  6. 链表Linked List
  7. 双向链表

线性结构
(1)线性结构作为常用的数据结构,其特点是数据元素之间存在一对一的线性关系
(2)线性结构两种不同的存储结构,即顺序存储结构(数组)和链式存储结构(链表)。顺序存储的线性表称为顺序表,顺序表中的存储元素是连续的
(3)链式存储的线性表成为链表,链表中的存储元素不一定是连续的,元素结点中存放数据元素以及相邻元素的地址信息
(4)线性结构常见的有:数组,队列,链表和栈
非线性结构
非线性结构包括:二维数组,多维数组,广义表,树结构,图结构

稀疏sparsearray数组

适用场景:适用二维数组记录棋盘,可以对数据进行压缩
基本介绍:但一个数组中大部分元素为0,或者为同一个值的数组时,可以使用稀疏数组来保存数组。
稀疏数组的处理方法时:
(1)记录数组一共有几行几列,有多少个不同的值
(2)把具有不同值的元素的行列及值记录在一个小规模的数组中,从而缩小程序的规模
在这里插入图片描述

二维数组转稀疏数组的思路: 1,遍历袁术的二维数组,得到有效数据的个数count
2,根据count就可以创建稀疏数组sparseArr
int [count+1][3]
3,将二维数组的有效数据存入到稀疏数组

稀疏数组转原始的二维数组思路:
(1)先读取稀疏数组的第一行,根据第一行的数据,创建原始的二维数组
(2)在读取稀疏数组后几行的数据,并赋给原始的二维数组即可

代码实现:

public static void main(String[] args) {
    
    
        //创建一个原始的二维数组 11*11
        //0表示没有棋子,1表示黑子,2表示白子
        int chessArr1[][] = new int [11][11];
        chessArr1[1][2] = 1;
        chessArr1[2][3] = 2;
        //输出原始的二维数组
        System.out.println("原始二维数组");
        for(int[] row : chessArr1) {
    
    
            for(int data:row) {
    
    
                System.out.printf("%d\t", data);
            }
            System.out.println();
        }

        //将二维数组转稀疏数组
        //先遍历二维数组得到非0数据的个数
        int count = 0;
        for(int i = 0;i < 11;i++) {
    
    
            for(int j = 0;j < 11;j++) {
    
    
                if(chessArr1[i][j] != 0)
                    count++;
            }
        }
        //创建对应的稀疏数组
        int sparseArr[][] = new int[count + 1][3];
        //给稀疏数组赋值
        sparseArr[0][0] = 11;
        sparseArr[0][1] = 11;
        sparseArr[0][2] = count;
        //遍历二维数组,将非0的值存放发到spaseArr中
        count = 0;
        for(int i = 0;i < 11;i++){
    
    
            for(int j = 0;j < 11;j++) {
    
    
                if(chessArr1[i][j] != 0) {
    
    
                    count++;
                    sparseArr[count][0] = i;
                    sparseArr[count][1] = j;
                    sparseArr[count][2] = chessArr1[i][j];
                }
            }

队列

队列是一个有序列表,可以用数组或是链表来实现
遵循先进先出的原则

代码实现:

class QueueArr{
    
    
    private int MaxSize;
    private int front;
    private int rear;
    private int[] arr;
    //创建一个队列
    public QueueArr(int max) {
    
    
        MaxSize = max;
        arr = new int[MaxSize];
        front = -1;
        rear = -1;
    }
    //判断队列是否为空
    public boolean ISEmpty(){
    
    
        return front == rear;
    }
    //判断队列是否已满
    public boolean IsFull() {
    
    
        return rear == MaxSize-1;
    }
    //出队
    public int GetQueue() {
    
    
        if(ISEmpty()) {
    
    
            throw new RuntimeException("队列是空的");
        }
        front++;
        return arr[front];
    }
    //入队
    public void AddQueue(int n) {
    
    
        if(IsFull()) {
    
    
            System.out.println("队列已经满了");
            return ;
        }
        rear++;
        arr[rear] = n;
    }
    //返回队头元素
    public int getHead() {
    
    
        if(ISEmpty()) {
    
    
            throw new RuntimeException("队列是空的");
        }
        return arr[front+1];
    }
    //显示对列里的所有数据
    public void ShowQueue() {
    
    
        if(ISEmpty()){
    
    
            System.out.println("队列是空的");
            return ;
        }
        for(int i = front+1;i <= rear;i++) {
    
    
            System.out.printf("arr[%d] = %d\n",i,arr[i]);
        }
    }

环形队列

思路:
(1)front变量的含义做一个调整:front就指向队列的第一个元素,也就是说arr[front]就是队列的第一个元素front的初始值=0;
(2)rear变量的含义做一个调整:rear指向队列的最后一个元素的后一个位置,因为希望空出一个空间作为约定,rear的初始值=0;
(3)当队列满时,条件是(rear + 1)%MaxSize = =front【满】 (4)对列为空的条件,rear== front空
(5)当我们这样分析,队列中有效的数据的个数(rear+MaxSize-front)%MaxSize

代码示例:

class CQueue{
    
    
    private int MaxSize;
    private int front;
    private int rear;
    private int[] arr;
    //初始化环形队列
    public  CQueue(int m) {
    
    
        MaxSize = m;
        arr = new int[MaxSize];
        front  = 0;
        rear = 0;
    }
    //计算环形队列的大小
    public int Size() {
    
    
        return (rear + MaxSize - front)%MaxSize;
    }
    //判断环形队列是否为空
    public boolean IsEmpty() {
    
    
        return rear == front;
    }
    //判断环形队列是否为满
    public boolean IsFull() {
    
    
        return (rear + 1)%MaxSize == front;
    }
    //环形对列进队
    public void AddCQueue(int n) {
    
    
        if(IsFull()) {
    
    
            System.out.println("环形队列已经满了");
            return ;
        }
        arr[rear] = n;
        rear++;
        if(rear > MaxSize) {
    
    

        }
        return ;
    }
    //环形队列出队
    public int GetCQueue() {
    
    
        if(IsEmpty()) {
    
    
            throw new RuntimeException("环形队列是空的");
        }
        int value = arr[front];
        front = (front+1)%MaxSize;
        return value;
    }
    //输出整个环形队列
    public void ShowCQueue() {
    
    
        if(IsEmpty()) {
    
    
            System.out.println("环形队列是空的");
            return;
        }
        int j = front;
        for(int i = front;i < front + Size();i++) {
    
    
            System.out.printf("arr[%d] = %d\n",i%MaxSize,arr[i%MaxSize]);
        }
    }
	//打印环形数组的首元素
    public void HeadCQueue() {
    
    
        if(IsEmpty()){
    
    
            System.out.println("环形队列为空");
        }
        System.out.println(arr[front]);
    }

链表(Linked List)

(1)链表是以结点的方式来存储
(2)每个结点包含data域:储存数据,next域:指向下一个结点
(3)链表分带头结点的链表和没有头结点的链表

代码示例:

扫描二维码关注公众号,回复: 14743458 查看本文章
class nodeList{
    
    
    //创建头结点
    Node head = new Node(0);

    //向链表中添加元素
    public void AddNode(Node node) {
    
    
        //先将指针指到头结点
        Node temp = head;
        //在顺着链表找到链表的尾部进行元素添加
        while(true) {
    
    
            if(temp.next == null) {
    
    
                break;
            }
            //指针指向下一个结点
            temp = temp.next;
        }
        //将插入元素插到列表末尾
        temp.next = node;
        node.next = null;
    }

    //删除指定data的节点
    public void delete(int data) {
    
    
        //判断链表是否为空
        if(this.head.next == null) {
    
    
            System.out.println("链表是空的,无法进行删除操作");
            return ;
        }
        Node temp = head;
        //判断链表是否找到相应的删除节点
        boolean flag = false;
        while(true) {
    
    
            if(temp.next == null)  {
    
    
                System.out.println("删除操作失败,没有找到相应的结点");
                break;
            }
            if(temp.next.data == data) {
    
    
                flag = true;
                break;
            }
            temp = temp.next;
        }
        if(flag) {
    
    
            temp.next = temp.next.next;
        }
    }

//链表翻转
    /*
    思路:
        遍历原先链表,将遍历的链表元素插入到临沂个新链表的最前面,完成翻转
     */
    public void reverse() {
    
    
        //判断链表为空或者只有一个结点(除了头结点)则直接返回,不用翻转
        if(head.next == null || head.next.next == null) {
    
    
            return ;
        }
        //定义一个新的头结点
        Node rHead = new Node(0);
        //定义一个循环原始链表的指针,将其初始值定义为原来链表的head.next
        Node cur = head.next;
        //定义一个指针指向当前结点的下一个结点
        Node next = cur.next;
        //遍历链表
        while(true) {
    
    

            //先记录下新链表的头结点的后一个结点
            Node temp = rHead.next;
            //将结点插入到新链表的最前面
            rHead.next = cur;
            //将原来链表cur后面的结点记录下来
            next = cur.next;
            //将插入后的结点的next置为原来rHead的next
            cur.next = temp;
            //判断如果当前结点的下一个结点为空,没么就已经遍历完整个链表了
            if(next == null) {
    
    
                break;
            }
            //将指针指向链表的下一个结点
            cur = next;
            //同时将指针后移
            next = cur.next;

        }
        //将元来的链表头指向现在的链表,完成链表翻转
        head.next = rHead.next;
    }

    //更改链表中相应位置元素的值
    public void upData(int formData, int newData) {
    
    
        //判断链表是否为空
        if(this.head.next == null) {
    
    
            System.out.println("链表是空的,无法更新数据");
            return;
        }
        //定义指针元素,进行遍历
        Node temp = head;
        //定义flag判断是否村在相应的要找的位置
        boolean flag = false;
        while(true) {
    
    
            if(temp.data == formData) {
    
    
                break;
            }
            if(temp.next == null) {
    
    
                flag = true;
                return;
            }
            temp = temp.next;
        }
        //如果要找的位置不存在,那么直接return
        if(flag) {
    
    
            System.out.println("更新失败,没有找到更新的内容");
            return ;
        }
        temp.data = newData;
    }

    //将元素插入到指定data(n)的后面
    public void AddNodeSite(Node node ,int n) {
    
    
        Node temp = head;
        //设置一个布尔值,来判断是否找到相应插入的位置
        boolean flag = false;
        //遍历链表,找到相应的位置
        while(true) {
    
    
            //找到相应位置,直接break
            if(temp.data == n) {
    
    
                break;
            }
            //没找到相应的位置,改变flag的值并且跳出循环
            if(temp.next == null) {
    
    
                flag = true;
                break;
            }
            temp = temp.next;
        }
        //如果没找到相应插入的位置则插入失败
        if(flag) {
    
    
            System.out.println("插入失败,没有找到合适的插入位置");
            return ;
        }
        //找到插入位置后,将前后结点都记录下来
        Node tempNext = temp.next;
        //将前置结点元素的next变为新的结点元素
        temp.next = node;
        //如果找到的位置是在链表的末尾,那么就将查睿的结点的next设置为null
        if(temp.next != null) {
    
    
            node.next = null;
        }
        else {
    
    
            node.next = tempNext;
        }

    }

    //输出链表
    public void list() {
    
    
        Node temp = head;
        //判断链表是否为空
        if(head.next == null) {
    
    
            System.out.println("链表是空的");
            return ;
        }
        temp = head.next;
        //一直循环输出,直到输出了最后一个元素为止
        while(true) {
    
    
            //因为在while循坏之外就已经将temp指向head后的元素,所以要先打印在判断
            System.out.println(temp);
            if(temp.next == null) {
    
    
                break;
            }
            //将指针指向下一个元素
            temp = temp.next;
        }
    }

}
//链表结点
class Node{
    
    
    public int data;
    public Node next;

    public Node(int data) {
    
    
        this.data = data;
    }
    //重写toString方法
    public String toString() {
    
    
        return "Node [data=" + data + "]";
    }

双向链表

(1)单向链表,查找的反向只能是一个反向,二双链表可以向前,向后查找
(2)单向量表不能自我伤处,只能靠辅助,二双向链表,则可以自我删除

代码实现:

class doubleListedList {
    
    
    //创建头结点
    DNode head = new DNode(0);

    //向链表中添加元素
    public void AddDNode(DNode node) {
    
    
        //先将指针指到头结点
        DNode temp = head;
        //在顺着链表找到链表的尾部进行元素添加
        while(true) {
    
    
            if(temp.next == null) {
    
    
                break;
            }
            //指针指向下一个结点
            temp = temp.next;
        }
        //将插入元素插到列表末尾
        temp.next = node;
        node.per = temp;
        node.next = null;
    }

    //删除指定data的节点
    public void delete(int data) {
    
    
        //判断链表是否为空
        if(this.head.next == null) {
    
    
            System.out.println("双向链表是空的,无法进行删除操作");
            return ;
        }
        DNode temp = head.next;
        //判断链表是否找到相应的删除节点
        boolean flag = false;
        while(true) {
    
    
            if(temp == null)  {
    
    
                System.out.println("删除操作失败,没有找到相应的结点");
                break;
            }
            if(temp.data == data) {
    
    
                flag = true;
                break;
            }
            temp = temp.next;
        }
        //找到相应删除的位置
        if(flag) {
    
    
            //将temp前置结点的next改成temp结点的next
            temp.per.next = temp.next;
            //如果temp的及诶单不是最后一个结点,那么就把temp后置结点的per改为temp的前置结点
            if(temp.next != null) {
    
    
                temp.next.per = temp.per;
            }
        }
    }

    //输出链表
    public void list() {
    
    
        DNode temp = head;
        //判断链表是否为空
        if(head.next == null) {
    
    
            System.out.println("链表是空的");
            return ;
        }
        temp = head.next;
        //一直循环输出,直到输出了最后一个元素为止
        while(true) {
    
    
            //因为在while循坏之外就已经将temp指向head后的元素,所以要先打印在判断
            System.out.println(temp);
            if(temp.next == null) {
    
    
                break;
            }
            //将指针指向下一个元素
            temp = temp.next;
        }
    }
}

//链表结点
class DNode{
    
    
    //存储数据的data
    public int data;
    //指向下一个结点的指针
    public DNode next;
    //指向上一个结点的指针
    public DNode per;
    public DNode(int data) {
    
    
        this.data = data;
    }
    //重写toString方法
    public String toString() {
    
    
        return "DNode [data=" + data + "]";
    }
}

猜你喜欢

转载自blog.csdn.net/qq_48627750/article/details/121179343