数据结构与算法

数据结构与算法

  • 1.数组模拟循环队列
    • 1.1. 实现的关键步骤:
    • 1.2. 实现代码
  • 2. 单链表
    • 2.1. 实现的关键步骤:
    • 2.2. 实现代码
    • 2.3. 拓展:

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、需要创建一个节点类(属性包括 数据域 和 指针域)
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),打印出栈的元素即可。

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

你可能感兴趣的:(#,数据结构与算法,数据结构,算法,排序算法)