数据结构与算法

Posted 执章学长

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了数据结构与算法相关的知识,希望对你有一定的参考价值。

数据结构与算法

1.数组模拟循环队列

1.1. 实现的关键步骤:

1、front:指向队列的第一个元素
2、rear:指向队列的最后一个元素的后一个位置
3、maxSize:队列的最大容量,可以在初始化时定义;如果没定义,可设置默认值。
4、front 和 rear 的初始值为0
5、判空条件:(rear + 1)% maxSize == front
6、判满条件:rear == front
7、入队:判满、rear指针后移、赋值
8、出队:判空、front指针后移
9、获取队首元素:获取 front 指向的元素
10、打印队列:从 front指向的元素到 front + 队列元素的个数
11、队列元素的个数:(rear + maxSize - front) % maxSize

1.2. 实现代码


class ArrayQueue
    // 表示数组的最大容量
    private int maxSize;
    //front 指向队列的第一个元素
    private int front;
    //rear 指向队列的最后一个元素的后一个位置
    private int rear;
    // 模拟队列的数组,用于存放元素
    private int[] arr;

    public ArrayQueue(int arrMaxSize) 
        // 初始化时,front 和 rear的初始值都为0,但由于int 本身默认值为 0 ,因此这里可以不用写
        //最大值由外部指定(由于牺牲掉一个位置,所以例如传入4实际上只有3个位置)
        maxSize = arrMaxSize;
        // 创建数组存储
        arr = new int[maxSize];
    

    // 判断队列是否满
    public boolean isFull() 
        return (rear  + 1) % maxSize == front;
    

    // 判断队列是否为空
    public boolean isEmpty() 
        return rear == front;
    

    // 添加数据到队列
    public void addQueue(int n) 
        // 判断队列是否满
        if (isFull()) 
            System.out.println("队列满,不能加入数据~");
            return;
        
        //直接将数据加入
        arr[rear] = n;
        //将 rear 后移, 这里必须考虑取模
        rear = (rear + 1) % maxSize;
    

    // 获取队列的数据, 出队列
    public int getQueue() 
        // 判断队列是否空
        if (isEmpty()) 
            // 通过抛出异常
            throw new RuntimeException("队列空,不能取数据");
        
        // 这里需要分析出 front是指向队列的第一个元素
        // 1. 先把 front 对应的值保留到一个临时变量
        // 2. 将 front 后移, 考虑取模
        // 3. 将临时保存的变量返回
        int value = arr[front];
        front = (front + 1) % maxSize;
        return value;
    

    // 显示队列的所有数据
    public void showQueue() 
        // 遍历
        if (isEmpty()) 
            System.out.println("队列空的,没有数据~~");
            return;
        
        // 思路:从front开始遍历,遍历多少个元素
        // 动脑筋
        for (int i = front; i < front + size() ; i++) 
            System.out.printf("arr[%d]=%d\\n", i % maxSize, arr[i % maxSize]);
        
    

    // 求出当前队列有效数据的个数
    public int size() 
        // rear = 2
        // front = 1
        // maxSize = 3
        return (rear + maxSize - front) % maxSize;
    

    // 显示队列的头数据, 注意不是取出数据
    public int headQueue() 
        // 判断
        if (isEmpty()) 
            throw new RuntimeException("队列空的,没有数据~~");
        
        return arr[front];
    


2. 单链表

2.1. 实现的关键步骤:

1、需要创建一个节点类(属性包括 数据域 和 指针域 next )
2、需要创建一个链表类(属性包括头节点,初始化链表时,需要创建一个头节点,头节点没有实际意义)
3、增加–找到要插入位置的节点的前一个节点,然后先将节点与后一个节点连接,再将前面的节点连接。关键代码:node.next = temp.next;temp.next = node;
4、删除–找到要删除的节点的前一个节点,然后将引用修改为下下个节点。关键代码:temp.next = temp.next.next;
5、查看–找到要查看的节点并返回。关键代码:return temp;
6、修改–找到要修改的节点,然后修改其值即可。关键代码:temp.值 = 新值;
7、打印链表:先跳过头节点,然后遍历链表直到 temp 指向空时,打印链表的信息。

2.2. 实现代码

package com.cs.testt;

import java.util.Scanner;

/**
 * @ClassName SingleLinkedListDemo
 * @Description TODO
 * @Author jiaqi
 * @Date 2022/2/22 14:27
 * @Version 1.0
 **/
public class SingleLinkedListDemo 
    public static void main(String[] args) 
        SingleLinkedList singleLinkedList = new SingleLinkedList();
        Scanner scanner = new Scanner(System.in);
        while (true) 
            System.out.println("------------------------");
            System.out.println("请输入以下字母:");
            System.out.println("a(add):添加");
            System.out.println("f(find):查找");
            System.out.println("u(update):更新");
            System.out.println("d(delete):删除");
            System.out.println("p(print):打印");
            System.out.println("o(out):退出程序");
            System.out.println("------------------------");
            String next = scanner.next();
            if (next.charAt(0) == 'o') 
                break;
            
            switch (next.charAt(0)) 
                case 'a':
                    System.out.println("请输入要添加的值:");
                    int item = scanner.nextInt();
                    singleLinkedList.add(item);
                    break;
                case 'f':
                    System.out.println("请输入要查找的值:");
                    int item1 = scanner.nextInt();
                    Node node = singleLinkedList.find(item1);
                    if (node == null) 
                        System.out.println("没有找到对应的值");
                     else 
                        System.out.println("找到的值为:" + node.num);
                    
                    break;
                case 'u':
                    System.out.println("请输入要旧的值:");
                    int oldN = scanner.nextInt();
                    System.out.println("请输入要新的值:");
                    int newN = scanner.nextInt();
                    boolean update = singleLinkedList.update(oldN, newN);
                    String s = update ? "更新成功" : "要更新的值根本不存在";
                    System.out.println(s);
                    break;
                case 'd':
                    System.out.println("请输入要删除的值:");
                    int item3 = scanner.nextInt();
                    Node delete = singleLinkedList.delete(item3);
                    if (delete == null) 
                        System.out.println("没有找到对应的值");
                     else 
                        System.out.println("已删除的值为:" + delete.num);
                    
                    break;
                case 'p':
                    String s1 = singleLinkedList.printList();
                    System.out.println(s1);
                    break;
                default:
                    System.out.println("-------------------------------");
                    System.out.println("|您的输入格式有误,请重新输入: |");
                    System.out.println("-------------------------------");
                    break;

            
        
        System.out.println("程序已退出...");
    



//链表类
class SingleLinkedList 
    private Node head;

    public SingleLinkedList() 
        this.head = new Node(0, null);
    

    //再链表的尾部添加一个节点
    public void add(int num) 
        Node temp = head;
        while (true) 
            if (temp.next == null) 
                break;
            
            temp = temp.next;
        
        Node node = new Node(num, null);
        temp.next = node;
    

    //    //根据编号添加一个节点(根据num从小到大排序)
//    public void addByOrder(Node node)
//        Node temp = head;
//        while (true)
//            if (temp.next == null)
//                break;
//            
//            if (temp.next.num >= node.num)
//                break;
//            
//            temp = temp.next;
//        
//
//        node.next = temp.next;
//        temp.next = node;
//    
    public Node find(int num) 
        Node temp = head.next;
        while (true) 
            if (temp == null) 
                break;
            
            if (temp.num == num) 
                break;
            
            temp = temp.next;
        
        return temp;
    

    public boolean update(int oldnum, int newNum) 
        Node temp = head.next;
        boolean flag = false;//是否找到旧值
        while (true) 
            if (temp == null) 
                break;
            
            if (temp.num == oldnum) 
                flag = true;
                break;
            
            temp = temp.next;
        
        if (flag) 
            temp.num = newNum;
        
        return flag;
    

    public Node delete(int num) 
        Node del = null;
        Node temp = head;
        while (true) 
            if (temp.next == null) //没有要找的节点
                break;
            
            if (temp.next.num == num) 
                del = temp.next;
                temp.next = temp.next.next;
                break;
            
            temp = temp.next;
        
        return del;

    

    public String printList() 
        StringBuffer stringBuffer = new StringBuffer();
        Node temp = head.next;
        int count = 1;
        while (true) 
            if (temp == null) 
                break;
            
            stringBuffer.append("第" + count + "个值: " + temp.num + "\\n");
            temp = temp.next;
            count++;
        
        return stringBuffer.toString();
    
    //计算节点的个数
    public int NodeNum()
        int count = 0;
        Node temp = head.next;
        while (true)
            if (temp == null)
                break;
            
            temp = temp.next;
            count++;
        
        return count;
    
    //查找单链表中的倒数第k个节点(双指针法)
    public Node findOrderByLast(int n)
        //设置两个指针
        Node temp1 = head.next;
        Node temp2 = head.next;
        while (true)
            if (temp1 == null)
                break;
            
            if (n<1)
                break;
            
            temp1 = temp1.next;
            n--;
        
        while (true)
            if (temp1 == null)
                break;
            
            temp1 = temp1.next;
            temp2 = temp2.next;
        
        return temp2;
    
    //反转链表
    public void reserve(Node head)
        Node reserveHead = new Node(0,null);
        Node temp = head.next;
        Node cur;
        while (true)
            if (temp == null)
                break;
            
            cur = temp;
            temp = temp.next;
            cur.next = reserveHead.next;
            reserveHead.next = cur;
        
        head.next = reserveHead.next;
    




//节点类
class Node 
    public int num;
    public Node next;

    public Node(int num, Node next) 
        this.num = num;
        this.next = next;
    


2.3. 拓展:

题目1:求一个单链表中节点的个数
方法:先创建一个变量作为计数器存储个数,初始值为 0 ,接着创建临时指针,循环遍历直到指针指向的节点为 null ,计数不断增加,最后跳出循环返回计数器。

题目2:查找单链表中的倒数第k个节点
方法1:双指针法。先让指针1和指针2指向第一个节点,接着指针1先走k个节点,然后让两个指针同时走,知道指针1走到null之后,指针2所指的节点即为所求。
方法2:先求出节点的个数(题目1),然后用节点个数减掉k得到需要走的步数,接着让指针走这么多步,即可。

题目3:单链表的反转。
方法:先创建一个新的头节点,然后遍历链表,当遍历到一个节点时将其放到新的头节点的后面的那个位置(每一个都如此),这样到最后的 temp == null 时停止,此时除了头节点外,其余都为所求,最后将旧的头节点指向新的头节点的下一个节点即可(即:head.next = nowHead.next;),然后head。

题目4:从头到尾打印单链表(不可破坏原先链表的结构)
方法:用栈结构 Stack ,遍历链表,并将每个节点压入栈(stack.push),接着循环栈,当栈不为空时,出栈(stack.pop),打印出栈的元素即可。

题目5:合并两个有序的单链表,并且合并之后还是有序的
方法:先创建一个新的头节点,然后创建两个指针指向两个链表的第一个节点(非头节点),然后再创建一个指针记录指向新的头节点(用户每次添加),循环直到有两个链表有一个指针为空为止,当哪个值比较小时,则让新链表的指针指向那个节点,并且新链表向后移动一个,指向的那个节点的指针也要向右移动,退出循环后,要将新链表的指针指向未结束的链表的指针的节点。最后返回头节点。

3. 双链表

3.1. 实现的关键步骤

1、需要创建一个节点类(属性包括 数据域 和指针域 next 和 pre )
2、需要创建一个链表类(属性包括头节点,与单链表类似)
3、增加–节点到链表尾部:与单链表类似,通过遍历,然后连接
4、增加–节点到指定的位置:与单链表类似,找到前一个节点,然后改变指针域
5、删除–可以自我删除,这个是双链表的特点,指针 temp 可以直接指向待删除的节点,然后通过改变指针指向,即可。
6、查看和修改–与单链表类似,直接找到指定的节点进行操作
7、打印链表–与单链表一样

3.2. 实现代码:

package com.cs.testt;

/**
 * @ClassName DoubleLinkedListDemo
 * @Description TODO
 * @Author jiaqi
 * @Date 2022/2/23 14:27
 * @Version 1.0
 **/
//双向链表
public class DoubleLinkedListDemo 



class DoubleLinkedList
    private TNode head;
    public DoubleLinkedList()
        this.head = new TNode(0,null,null);
    
    //添加节点到尾部
    public void addLast(TNode tNode)
        TNode temp = head;
        while (true)
            if (temp.next == null)
                break;
            
            temp = temp.next;
        
        temp.next = tNode;
        tNode.pre = temp;
    
    //根据值的大小(从小到大)添加节点
    public void addOrder(TNode tNode)
        TNode temp = head;
        while (true)
            if (temp.next == null)
                break;
            
            if (temp.next.num >=tNode.num)
                break;
            
            temp = temp.next;
        
        if (temp.next == null)
            temp.next = tNode;
            tNode.pre = temp;
        else 
            //没名字的先来
            temp.next一次请求对多条数据进行排序的算法

数据结构与算法 —— 二叉树

JAVA数据结构与算法之二叉树

数据结构与算法笔记(十六)—— 二叉搜索树

数据结构与算法面试题80道(11)

数据结构与算法问题 二叉搜索树