没长正的技术专栏 勤动手、多思考

数据结构

2017-02-01
mzz

阅读:

2021-07-13

目的

程序 = 数据结构 + 算法

了解数据结构、算法思想、优缺点、合理运用到项目中, 常见算法:

一、数据结构

1.

调用栈: 后进先出(先进后出)
调用栈可能很长,需要占用很多的内存     --->竖着的 长方形
不能用于查找

优化:采用循环、尾递归

扩展:思考代码中方法名称、参数名称 存放的位置

实例:递归算法、函数调用(JVM)、深度优先遍历、两个栈实现一个队列、实现括号验证

1.1 括号验证

// https://leetcode-cn.com/problems/valid-parentheses/
//括号验证 :  遍历字符, ([{ 入栈,)]} 时,出栈校验   
class Solution {
    public boolean isValid(String s) 
    {
        if(s == null || s.length()==0)
        {
            return true;
        }
        Stack<Character> stack = new Stack<>();
        for(char c:s.toCharArray())
        {
                        
            if(c=='(' || c=='[' || c=='{')
            {
                stack.push(c);
            }
            if(c ==')')
            {
                if(stack.isEmpty() || stack.pop()!='(')
                {    
                    return false;
                }
            }
            if(c ==']')
            {
                if(stack.isEmpty() || stack.pop()!='(')
                {    
                    return false;
                }
            }
            if(c =='}')
            {
                if(stack.isEmpty() || stack.pop()!='{')
                {    
                    return false;
                }
            }
        }
        
        return stack.isEmpty();
    }
}
// 注意: 
/**
 *  1. 基础用法: String.toCharArray()、length() 需要加括号。
 *  2. 栈初始化: Stack<Character> stack = new Stack<>()
 *  3. 最后一步: stack.isEmpty();       // [
 *	4. 校验(先自查 )
 */

1.2 最小栈

// 取出栈内最小值。   思路: 同时操作两个栈,同时入栈、同时出栈。   =》 取栈 最大
class MinStack {

    /** initialize your data structure here. */
    Stack<Integer> stack;
    Stack<Integer> minStack;
    public MinStack() {
        stack = new Stack<>();
        minStack = new Stack<>();

    }
    
    public void push(int val) {
        stack.push(val);
        if(minStack.isEmpty() || val < minStack.peek())
        {
            minStack.push(val);
        }
        else
        {
            minStack.push(minStack.peek());
        }
    }
    
    public void pop() {
       minStack.pop();
       stack.pop();
    }
    
    public int top() {
       return stack.peek();
    }
    
    public int getMin() {
        return minStack.peek();
    }
}

/**
 * Your MinStack object will be instantiated and called as such:
 * MinStack obj = new MinStack();
 * obj.push(val);
 * obj.pop();
 * int param_3 = obj.top();
 * int param_4 = obj.getMin();
 */

1.3 最大区间

class MaxSection {

    //int[] numbers ={5,2,3,4,1}
    public int getMax(int[] numbers)
    {
        //如果数据为空
        if(numbers==null ||numbers.length ==0)
        {
            return 0;
        }
        
        //保存的是索引
        Stack<Integer> stack = new Stack<>();
        int max=0;
        int[] sum = new int[numbers.length+1];

        for(int i = 1;i<numbers.length;i++)
        {
            sum[i] = sum[i-1]+numbers[i-1];
        }
        
        for(int i=0;i<numbers.length;i++)
        {
            while(!stack.isEmpty() && numbers[i]<numbers[stack.peek()])
            {
                int index = stack.pop();
                int left = i;
                int right =i;
                if(stack.isEmpty())
                {
                    left = 0;
                }else
                {
                    left = index;
                }
                max = Math.max(max,numbers[index] * (sum[right]-sum[left])));
            }
            stack.push(i);
        }
        
        //最后一部分数据都是  从小到大排列,则未取完
        while(!stack.isEmpty())
        {
            int index = stack.pop;
            int left = numbers.length;
            int right = numbers.length;
            if(stack.isEmpty())
            {
                left = 0;
            }else
            {
                left = index;
            }
            max = Math.max(max,numbers[index] * (sum[right]-sum[left])));
        }
        retrun max;
    }
}

1.4 两个栈实现队列

  1. 分成两段: 第一个栈存新来的数据,第二个栈则取;

  2. 当第二个栈没有数据时,则从第一个栈,取出数据,放置到第二个栈(新来的数据在最上面 )。
  3. 当要队列取数是,则从第二个栈取数。

2. 队列

实例:公交车站,排队等车、系统中各个资源管理、消息缓冲区管理、广度优先搜索
特点:先进先出

5.散列表

 定义:根据关键码值(Key value)而直接进行访问的数据结构。也就是说,它通过把关键码值映射到表中一个位置来访  	  问记录,以加快查找的速度。这个映射函数叫做散列函数,存放记录的数组叫做散列表。
 
 内部机制: 实现、冲突、散列函数

 散列函数:
    <1.它必须是一致的(同一输入,输出结果相同)
    <2.它应将不同的输入映射到不同的数字 ** (没有冲突的情况) 很难

   (1)散列函数很重要(最理想的情况:将键均匀映射到散列的不同位置)
   (2)散列的链表不能太长,影响查询效率
   
   构造方法:
   	(1)直接定址法(关键码本身和地址之间存在某个线性函数关系时,散列函数取为关键码的线性函数,即:H(key)=a*key+b,a、b均为常数。)  查找表较小且连续,不常用
   	(2)除留余数法(通过选择适当的正整数p,按计算公式H(K)=K mod p来计算关键码K的散列地址。
)  常用:Integer等数据类型 源码中hashcode
	(3)平方取中法(将关键码K平方,取K^2中间几位作为其散列地址H(K)的值。
)
	(4)随机数法(采用随机函数作为散列函数H(Key)=random(Key),其中random为随机函数。)
        当关键码长度不等时,采用该方法较恰当。
        
    解决Hash冲突的处理方法:
    (1)再hash
    (2)缓冲区
    (3)开放定址法(从发生冲突位置的下一个位置开始寻找空的散列地址。发生冲突时,线性探测下一个散列地址是:Hi=(H(key)+di)%m,(di=1,2,3...,m-1))
    (4)拉链法()
    
 实例: HashTable、HashMap、加密算法、查找、海量数据处理

    <1.模拟映射关系 -->将散列用于查找 (通过姓名查询电话号码)
    <2.防止重复(投票站投票,不允许1人多投)
    <3.将散列用于缓存(网站缓存,不用每次请求服务器)

性能:

    1.较低的填充因子(散列包含的元素个数/位置总数)
    2.良好的散列函数(各个语言内置有散列函数)

6.图

图有节点和边组成。

概念: 邻接表、邻接矩阵、邻接点、度

7.有向图

有方向,单向关系

8.无向图

无方向

9.树

树是一种特殊的图。
实例:家谱

最小生成树:n个顶点的连通图中选择n-1条边,构成权值之和最小的连通子图,被称为最小生成树。

扩展:二叉树、B-树B+树红黑树、堆、伸展树。

参考

«算法图解»

  • ”程序员小灰“ 公众号 (推荐)

约瑟夫问题

  • 网课(腾讯课堂)

欢迎拍砖,多多交流,转载请注明出处:[没长正的技术专栏](http://blog.meizhangzheng.com) 如涉及侵权问题,请发送邮件到xsj34567@163.com,如情况属实本人将会尽快删除。


上一篇 数据结构之堆

下一篇 数据结构之树

Comments

Content