数据结构二:栈+队列+递归(DataWhale系列)

简介: Datawhale 系列数据结构Task2.1 栈2.1.1用数组实现一个顺序栈public class ArrayStack<T> { private T [] data; private int size; private int cnt; @...

Datawhale 系列数据结构

Task2.1 栈

2.1.1用数组实现一个顺序栈

public class ArrayStack<T> {
    private T [] data;
    private int size;
    private int cnt;
    
    @SuppressWarnings("unchecked")
    public ArrayStack(){
        data= (T[]) new Object [10]; 
        cnt = 0;
        size =10;
    }
    
    public void push(T t){
        if(cnt>=size){
            data=Arrays.copyOf(data, data.length*2);
            size*=2;
        }
        data[size] = t;
        cnt++;
    }
    public T peek(){
        if (cnt==0) {
            throw new EmptyStackException();
        }
        return data[cnt];
    }
    public T pop(){
        if (cnt==0) {
            throw new EmptyStackException();
        }
        cnt--;
        return data[cnt];
    }
    public int search(T t){
        for(int i=cnt;i>0;i--){
            if(data[i]==t)
                return i;
        }
        return -1;
    }
    public boolean isEmpty(){
        return cnt==0;
    }
}

2.1.2 用链表实现一个链式栈

public class ListStack<T> {
    private List<T> data;
    private int cnt;
    
    public ListStack(){
        data= new LinkedList<T>(); 
        cnt = 0;
    }
    
    public void push(T t){
        data.add(t);
        cnt++;
    }
    public T peek(){
        if (cnt==0) {
            throw new EmptyStackException();
        }
        return data.get(cnt);
    }
    public T pop(){
        if (cnt==0) {
            throw new EmptyStackException();
        }
        T t=data.remove(cnt);
        cnt--;
        return t; 
    }
    public int search(T t){
        for(int i=cnt;i>0;i--){
            if(data.get(i)==t)
                return i;
        }
        return -1;
    }
    public boolean isEmpty(){
        return cnt==0;
    }
}

2.1.3 编程模拟实现一个浏览器的前进后退功能

public class BrowserSimula {
    public static void main(String[] args) {
        Browser b1=new Browser();
        b1.open();
        b1.open();
        b1.open();
        b1.open();
        System.out.println(b1.backward());
        System.out.println(b1.backward());
        System.out.println(b1.forward());
        System.out.println(b1.forward());
    }
}

class Browser{
    private Stack<Integer> s1;
    private Stack<Integer> s2;
    int cnt;
    
    Browser(){
        s1=new Stack<Integer>();
        s2=new Stack<Integer>();
        cnt=0;
    }
    /**
     * 点开一个新的链接
     */
    public void open(){
        cnt++;
        s1.push(cnt);
    }
    //后退
    public Integer backward(){
        if(cnt==0)
            throw new ArrayIndexOutOfBoundsException(cnt);
        Integer a =s1.pop();
        s2.push(a);
        return s1.peek();
    }
    //前进
    public Integer forward(){
        if(s2.isEmpty())
            throw new ArrayIndexOutOfBoundsException(cnt);
        Integer a =s2.pop();
        s1.push(a);
        return a;
    }
    
}

2.1.4 练习

//Valid Parentheses(有效的括号)
 private HashMap<Character, Character> mappings;

  public Solution() {
    this.mappings = new HashMap<Character, Character>();
    this.mappings.put(')', '(');
    this.mappings.put('}', '{');
    this.mappings.put(']', '[');
  }

  public boolean isValid(String s) {
    Stack<Character> stack = new Stack<Character>();

    for (int i = 0; i < s.length(); i++) {
      char c = s.charAt(i);
      if (this.mappings.containsKey(c)) {
        char topElement = stack.empty() ? '#' : stack.pop();
        if (topElement != this.mappings.get(c)) {
          return false;
        }
      } else {
        stack.push(c);
      }
    }
    return stack.isEmpty();
  }
//Longest Valid Parentheses(最长有效的括号)[作为可选]
/*dp 方法:
我们用 dp[i] 表示以 i 结尾的最长有效括号;

1 当 s[i] 为 ( , dp[i] 必然等于0,因为不可能组成有效的括号;
2 那么 s[i] 为 )
    2.1 当 s[i-1] 为 (,那么 dp[i] = dp[i-2] + 2;
    2.2 当 s[i-1] 为 ) 并且 s[i-dp[i-1] - 1] 为 (,那么 dp[i] = dp[i-1] + 2 + dp[i-dp[i-1]-2];
时间复杂度:O(n)
*/
public int longestValidParentheses(String s) {
    if (s == null || s.length() == 0) return 0;
    int[] dp = new int[s.length()];
    int res = 0;
    for (int i = 0; i < s.length(); i++) {
        if (i > 0 && s.charAt(i) == ')') {
            if (s.charAt(i - 1) == '(') {
                dp[i] = (i - 2 >= 0 ? dp[i - 2] + 2 : 2);
            } else if (s.charAt(i - 1) == ')' && i - dp[i - 1] - 1 >= 0 && s.charAt(i - dp[i - 1] - 1) == '(') {
                dp[i] = dp[i - 1] + 2 + (i - dp[i - 1] - 2 >= 0 ? dp[i - dp[i - 1] - 2] : 0);
             }
        }
    res = Math.max(res, dp[i]);
    }
    return res;
}

//Evaluate Reverse Polish Notatio(逆波兰表达式求值)
 public int evalRPN(String[] tokens) {
        Stack<Integer> stack = new Stack<>();
        for (int i = 0 ;i < tokens.length;i++){
            String str = tokens[i];
            if (str.length() == 1){
                char ch = str.charAt(0);
                if (ch-'0' >= 0 && ch - '0' <= 9 ){
                    Integer a = Integer.valueOf(str);
                    stack.push(a);
                }                    
                else{
                    if (stack.size() < 2)
                        return 0;
                    int num2 = stack.pop();
                    int num1 = stack.pop();
                    switch(ch){
                        case '+':                            
                            stack.push(num1 + num2);
                            break;
                        case '-':
                            stack.push(num1 - num2);
                            break;
                        case '*':
                            stack.push(num1 * num2);
                            break;
                        case '/':
                            stack.push(num1 / num2);
                            break;
                    }
                    
                }
            }else{
                int n = Integer.valueOf(str);
                stack.push(n);
            }
        }
        return stack.pop(); 
    }

TASK2.2 队列

2.2.1 用数组实现一个顺序队列

public class ArrayQueue<T>  {
    private T [] data ;
    private int cnt;//元素个数    
    private int size;//队列长度
    
    @SuppressWarnings("unchecked")
    public ArrayQueue(){
        data =(T[]) new Object [10];
        cnt = 0;
        size = 10;
    }
    @SuppressWarnings("unchecked")
    public ArrayQueue(int size){
        data =(T[]) new Object [size];
        cnt = 0;
        this.size = size;
    }
    
    public void add(T t){
        if(cnt>=size){
            throw new IllegalStateException();
        }
        data[cnt]=t;
        cnt++;
    }
    
    public T remove(){
        if(cnt<0){
            throw new NoSuchElementException();
        }
        T t= data[0];
        data = Arrays.copyOfRange(data,0,size);
        cnt--;
        return t;
        
    }    
    public boolean offer(T t){
        if(cnt>=size){
            return false;
        }
        data[cnt]=t;
        cnt++;
        return true;
    }    
    public boolean pull(T t){
        if(cnt<0){
            return false;
        }
        data = Arrays.copyOfRange(data,0,size);
        cnt--;
        return true;
    }
    //返回队列头元素
    public T element(){
        return data[0];    
    }     
    public boolean isEmpty(){
        return cnt==0 ;
    }
    public boolean isFull(){
        return cnt==size;
    }
}

2.2.2 用链表实现一个链式队列

public class ListQueue<T> {
    private List<T> data ;
    private int cnt;//元素个数
    
    private int size;//队列长度(用链表的话这里可以强行定义)
    
    public ListQueue(){
        data =new LinkedList<T>();
        cnt = 0;
        size = 10;
    }

    public void add(T t){
        data.add(t);
        cnt++;
    }
    
    public T remove(){
        if(cnt<0){
            throw new NoSuchElementException();
        }
        T t= data.remove(cnt);
        cnt--;
        return t;
        
    }
    
    public boolean offer(T t){
        if(cnt>=size){
            return false;
        }
        data.add(t);
        cnt++;
        return true;
    }
    
    public boolean pull(T t){
        if(cnt<0){
            return false;
        }
        data.remove(cnt);
        cnt--;
        return true;
    }
    //返回队列头元素
    public T element(){
        return data.get(0);    
    }
    
    public boolean isEmpty(){
        return cnt==0 ;
    }
    public boolean isFull(){
        return cnt==size;
    }
}

2.2.3 实现一个循环队列

public class MyCircularQueue {
    private final int capacity;
    private final int[] array;
    private int head = 0;
    private int tail = 0;
    private int count = 0;

    /**
     * Initialize your data structure here. Set the size of the queue to be k.
     */
    public MyCircularQueue(int k) {
        this.capacity = k;
        this.array = new int[this.capacity];
    }

    /**
     * Insert an element into the circular queue. Return true if the operation is successful.
     */
    public boolean enQueue(int value) {
        //队列已满
        if (count == capacity) {
            return false;
        }

        //队列为空, 重新设置头部
        if (count == 0) {
            head = (head == capacity) ? 0 : head;
            tail = head;
            array[head] = value;
            count++;
            return true;
        }

        //队列未满 (有空位)
        if (tail == capacity - 1) {
            //tail 达到 maxIndex, 重置为 0
            tail = 0;
        } else {
            //tail 未达到 maxIndex, tail++
            tail++;
        }
        array[tail] = value;
        count++;
        return true;
    }

    /**
     * Delete an element from the circular queue. Return true if the operation is successful.
     */
    public boolean deQueue() {
        if (count == 0) {
            //队列为空
            return false;
        }
        count--;
        head++;
        return true;
    }

    /**
     * Get the front item from the queue.
     */
    public int Front() {
        if (count == 0 ) {
            return -1;
        }
        return array[head];
    }

    /**
     * Get the last item from the queue.
     */
    public int Rear() {
        if (count == 0 ) {
            return -1;
        }
        return array[tail];
    }

    /**
     * Checks whether the circular queue is empty or not.
     */
    public boolean isEmpty() {
        return count == 0;
    }

    /**
     * Checks whether the circular queue is full or not.
     */
    public boolean isFull() {
        return count == capacity;
    }
}

2.2.4 练习

//Design Circular Deque(设计一个双端队列)
class MyCircularDeque {
    public int k;
    public int[] numbers;
    public int head;
    public int tail;
    /** Initialize your data structure here. Set the size of the deque to be k. */
    public MyCircularDeque(int k) {
        numbers=new int[k+1];
        head=0;
        tail=0;
        this.k=k;
    }
    
    /** Adds an item at the front of Deque. Return true if the operation is successful. */
    public boolean insertFront(int value) {
        if(isFull())
            return false;
        else{
            head=(head+k)%(k+1);
            numbers[head]=value;
            return true;
        }
    }
    
    /** Adds an item at the rear of Deque. Return true if the operation is successful. */
    public boolean insertLast(int value) {
        if(isFull())
            return false;
        else{
            numbers[tail]=value;
            tail=(tail+1)%(k+1);
            return true;
        }
    }
    
    /** Deletes an item from the front of Deque. Return true if the operation is successful. */
    public boolean deleteFront() {
         if(isEmpty())
            return false;
        else{
            head=(head+1)%(k+1);
            return true;
        }
    }
    
    /** Deletes an item from the rear of Deque. Return true if the operation is successful. */
    public boolean deleteLast() {
         if(isEmpty())
            return false;
        else{
            tail=(tail+k)%(k+1);
            return true;
        }
    }
    
    /** Get the front item from the deque. */
    public int getFront() {
        if(isEmpty())
            return -1;
        return numbers[head];
    }
    
    /** Get the last item from the deque. */
    public int getRear() {
        if(isEmpty())
            return -1;
        return numbers[(tail+k)%(k+1)];
    }
    
    /** Checks whether the circular deque is empty or not. */
    public boolean isEmpty() {
        return tail==head;
    }
    
    /** Checks whether the circular deque is full or not. */
    public boolean isFull() {
        return (tail+1)%(k+1)==head;
    }
}
//Sliding Window Maximum(滑动窗口最大值)
class Solution {
    public int[] maxSlidingWindow(int[] nums, int k) {
        if(k==0){
            return new int[0];
        }
        List<Integer> list = new ArrayList<>();//存放窗口内的数字
        int max = Integer.MIN_VALUE;//窗口内的最大数字
        for(int i = 0; i<k;i++){
            if(max<nums[i]){
                max = nums[i];
            }
            list.add(nums[i]);
        }
        int[] res = new int[nums.length - k + 1];//要返回的结果数据
        res[0] = max;
        for(int i = k; i < nums.length;i++){
            int z =list.remove(0);//移走第一位数并插入新的一位数
            list.add(nums[i]);
            if(z!=max){//移走的数不是max,只需判断max与新插入的数哪个大
                if(nums[i]> max){
                    max = nums[i];
                }
                res[i-k+1] = max;
            }else{//移走的数是max,重新判断列表中哪个数是最大的
                if(!list.contains(max)){
                    max = Integer.MIN_VALUE;
                    for(Integer num : list){
                        if(max<num){
                            max = num;
                        }
                    }
                }else{
                    if(nums[i]> max){
                        max = nums[i];
                    }
                }    
            }
            res[i-k+1] = max;
        }
        return res;
    }
}

3 递归

3.1 编程实现斐波那契数列求值 f(n)=f(n-1)+f(n-2)

public static int Fibe(int n){
        if(n==1) return 1;
        if(n==2) return 1;
        return Fibe(n-1)+Fibe(n-2);
    }

3.2 编程实现求阶乘 n!

public static int factorial(int n){
        if(n==1) return 1;
        return factorial(n-1)*n;
    }

3.3 编程实现一组数据集合的全排列

class Solution {
    List<List<Integer>> res = new ArrayList<>();
    
    public List<List<Integer>> permute(int[] nums) {
        permition(nums, 0, nums.length-1);
        return res;
    }
    
    public void permition(int[] nums, int p, int q){
        if(p==q){
            res.add(arrayToList(nums));
        }
        for(int i = p; i <= q; i++){
            swap(nums, i, p);
            permition(nums, p+1, q);
            swap(nums, i,p);
        }
    }
    
    private List<Integer> arrayToList(int[] nums){
        List<Integer> res = new ArrayList<>();
        for(int i = 0; i < nums.length; i++){
            res.add(nums[i]);
        }
        
        return res;
    }
    
    private void swap(int[] nums, int i, int j){
        int temp = nums[i];
        nums[i] = nums[j];
        nums[j] = temp;
    }
}

3.4 练习

// Climbing Stairs(爬楼梯)
//直接递归,但是直接递归leetcode竟然不能通过,于是又方法2
class Solution {
    public int climbStairs(int n) {
        if(n==1) return 1;
        if(n==2) return 2;
        return  climbStairs(n-1)+climbStairs(n-2);
    }
}

//非递归放啊
class Solution {
    public int climbStairs(int n) {
        int [] ways = new int[n+1];
        ways[0] = 0;
        for (int i = 1;i<ways.length;i++){
            if (i < 3 ){
                ways[i] = i;
            }else {
                ways[i] = ways[i-1] + ways[i-2];
            }
        }
        return ways[n];
    }
}
目录
相关文章
|
7月前
|
前端开发 Java
java实现队列数据结构代码详解
本文详细解析了Java中队列数据结构的实现,包括队列的基本概念、应用场景及代码实现。队列是一种遵循“先进先出”原则的线性结构,支持在队尾插入和队头删除操作。文章介绍了顺序队列与链式队列,并重点分析了循环队列的实现方式以解决溢出问题。通过具体代码示例(如`enqueue`入队和`dequeue`出队),展示了队列的操作逻辑,帮助读者深入理解其工作机制。
246 1
|
5月前
|
编译器 C语言 C++
栈区的非法访问导致的死循环(x64)
这段内容主要分析了一段C语言代码在VS2022中形成死循环的原因,涉及栈区内存布局和数组越界问题。代码中`arr[15]`越界访问,修改了变量`i`的值,导致`for`循环条件始终为真,形成死循环。原因是VS2022栈区从低地址到高地址分配内存,`arr`数组与`i`相邻,`arr[15]`恰好覆盖`i`的地址。而在VS2019中,栈区先分配高地址再分配低地址,因此相同代码表现不同。这说明编译器对栈区内存分配顺序的实现差异会导致程序行为不一致,需避免数组越界以确保代码健壮性。
118 0
栈区的非法访问导致的死循环(x64)
232.用栈实现队列,225. 用队列实现栈
在232题中,通过两个栈(`stIn`和`stOut`)模拟队列的先入先出(FIFO)行为。`push`操作将元素压入`stIn`,`pop`和`peek`操作则通过将`stIn`的元素转移到`stOut`来实现队列的顺序访问。 225题则是利用单个队列(`que`)模拟栈的后入先出(LIFO)特性。通过多次调整队列头部元素的位置,确保弹出顺序符合栈的要求。`top`操作直接返回队列尾部元素,`empty`判断队列是否为空。 两题均仅使用基础数据结构操作,展示了栈与队列之间的转换逻辑。
|
9月前
|
算法 调度 C++
STL——栈和队列和优先队列
通过以上对栈、队列和优先队列的详细解释和示例,希望能帮助读者更好地理解和应用这些重要的数据结构。
228 11
|
9月前
|
DataX
☀☀☀☀☀☀☀有关栈和队列应用的oj题讲解☼☼☼☼☼☼☼
### 简介 本文介绍了三种数据结构的实现方法:用两个队列实现栈、用两个栈实现队列以及设计循环队列。具体思路如下: 1. **用两个队列实现栈**: - 插入元素时,选择非空队列进行插入。 - 移除栈顶元素时,将非空队列中的元素依次转移到另一个队列,直到只剩下一个元素,然后弹出该元素。 - 判空条件为两个队列均为空。 2. **用两个栈实现队列**: - 插入元素时,选择非空栈进行插入。 - 移除队首元素时,将非空栈中的元素依次转移到另一个栈,再将这些元素重新放回原栈以保持顺序。 - 判空条件为两个栈均为空。
|
C语言
【数据结构】栈和队列(c语言实现)(附源码)
本文介绍了栈和队列两种数据结构。栈是一种只能在一端进行插入和删除操作的线性表,遵循“先进后出”原则;队列则在一端插入、另一端删除,遵循“先进先出”原则。文章详细讲解了栈和队列的结构定义、方法声明及实现,并提供了完整的代码示例。栈和队列在实际应用中非常广泛,如二叉树的层序遍历和快速排序的非递归实现等。
1019 9
|
存储 算法
非递归实现后序遍历时,如何避免栈溢出?
后序遍历的递归实现和非递归实现各有优缺点,在实际应用中需要根据具体的问题需求、二叉树的特点以及性能和空间的限制等因素来选择合适的实现方式。
287 59
|
10月前
|
存储 C语言 C++
【C++数据结构——栈与队列】顺序栈的基本运算(头歌实践教学平台习题)【合集】
本关任务:编写一个程序实现顺序栈的基本运算。开始你的任务吧,祝你成功!​ 相关知识 初始化栈 销毁栈 判断栈是否为空 进栈 出栈 取栈顶元素 1.初始化栈 概念:初始化栈是为栈的使用做准备,包括分配内存空间(如果是动态分配)和设置栈的初始状态。栈有顺序栈和链式栈两种常见形式。对于顺序栈,通常需要定义一个数组来存储栈元素,并设置一个变量来记录栈顶位置;对于链式栈,需要定义节点结构,包含数据域和指针域,同时初始化栈顶指针。 示例(顺序栈): 以下是一个简单的顺序栈初始化示例,假设用C语言实现,栈中存储
500 77
|
10月前
|
存储 C++ 索引
【C++数据结构——栈与队列】环形队列的基本运算(头歌实践教学平台习题)【合集】
【数据结构——栈与队列】环形队列的基本运算(头歌实践教学平台习题)【合集】初始化队列、销毁队列、判断队列是否为空、进队列、出队列等。本关任务:编写一个程序实现环形队列的基本运算。(6)出队列序列:yzopq2*(5)依次进队列元素:opq2*(6)出队列序列:bcdef。(2)依次进队列元素:abc。(5)依次进队列元素:def。(2)依次进队列元素:xyz。开始你的任务吧,祝你成功!(4)出队一个元素a。(4)出队一个元素x。
411 13
【C++数据结构——栈与队列】环形队列的基本运算(头歌实践教学平台习题)【合集】
|
10月前
|
存储 C语言 C++
【C++数据结构——栈与队列】链栈的基本运算(头歌实践教学平台习题)【合集】
本关任务:编写一个程序实现链栈的基本运算。开始你的任务吧,祝你成功!​ 相关知识 初始化栈 销毁栈 判断栈是否为空 进栈 出栈 取栈顶元素 初始化栈 概念:初始化栈是为栈的使用做准备,包括分配内存空间(如果是动态分配)和设置栈的初始状态。栈有顺序栈和链式栈两种常见形式。对于顺序栈,通常需要定义一个数组来存储栈元素,并设置一个变量来记录栈顶位置;对于链式栈,需要定义节点结构,包含数据域和指针域,同时初始化栈顶指针。 示例(顺序栈): 以下是一个简单的顺序栈初始化示例,假设用C语言实现,栈中存储整数,最大
215 9

热门文章

最新文章

下一篇
oss云网关配置