Java常用数据结构及应用(一)

Java常用数据结构及应用:数组,栈和队列

数据结构

数据结构是为了让计算机能够更合理地组织数据、更高效地存储和处理数据而产生的。计算机中的数据往往具有复杂的关系,因此存取效率,可扩展性,顺序性,可排序性都是数据结构中的重要指标。
数据结构贯穿程序设计的始终。

数据表示数据处理
抽象逻辑结构基本运算
实现存储结构算法
评价不同数据结构的比较及算法分析

逻辑结构: 逻辑结构就是数据之间的关系。可以分为两种:线性结构和非线性结构。
线性结构:有且只有一个开始结点和一个终端结点,且所有结点都最多只有一个直接前驱和一个直接后继。如线性表,典型的有:顺序表、链表、栈(顺序栈、链栈)和队列(顺序队列、链队列)等。
非线性结构:每个结点可以有不止一个直接前驱和直接后继。常见的非线性结构有:等。
存储结构: 存储结构也就是物理结构,是逻辑结构的存储映像。常见的存储结构有顺序存储、链式存储、索引存储以及散列存储(哈希表)。可以将存储结构理解为逻辑结构在计算机中的表现形式。
基本运算: 包括数据的增删改查和排序,根据逻辑结构来定义,根据算法和存储结构来实现。
算法: 算法可以理解为解决问题的步骤。对于数据结构来说,如何插入、寻找和删除一个数据项以及如何迭代地访问某一数据结构中的各数据项等都属于算法的范畴。另一个我们熟知的范畴就是排序。

常用数据结构

数据结构可以划分为三类:线性(排序)结构,树形结构,图形结构。
Java语言中最常用的数据结构包括数组、队列、链表等等。

1.数组Array

数组介绍
数组是用来存放同一种数据类型的结构,在内存中的分配是连续的。数组中的元素通过数组下标进行访问,数组下标从0开始。

// 声明一维数组
int[] array1 = new int[3]; //指定数组长度
int[] array2 = {1,2,3,4,5}; //直接给定数组元素
//声明二维数组
int[][] array3 = new int[n][]; //默认值为null
int[][] array4 = {{1,2,3},{4,5,6},{7,8,9},{}};
// 遍历数组, 利用 length 属性
for(int i = 0 ; i < array2.length ; i++){
    System.out.println(array2[i]);
}

数组工具类Arrays
Arrays类是JDK提供的专门用于操作数组中数据的工具类,位于java.util包中。
常用方法表

方法声明功能描述
public static List asList(T… a)返回由指定数组支持的固定大小的列表
public static String toString(int[] a)返回指定数组的内容的字符串表示形式
public static void sort(int[] a)按照数字顺序排列指定的数组
public static int[] copyof(int[] a,int length)返回与a元素相同的长度为length的新数组
  1. 数组转集合(asList)
String[] name = {"a","ab","abc","abcd"};
List<String> list = Arrays.asList(name); 
for(String li: list){
	String str = li;
	System.out.print(str + " ");
}
//输出结果
//a ab abc abcd 
  1. 数组转字符串

该方法并不是对 Object 类 toString() 方法的重写,只是用于返回指定数组的字符串形式数组。

int[] arr = {9, 8, 3, 5, 2};
String arrStr = Arrays.toString(arr);
System.out.println(arrStr);
//输出结果
//[9, 8, 3, 5, 2]
  1. 排序
int[] arr = {9, 7, 5, 3, 1};
Arrays.sort(arr);
for(int x=0; x<arr.length; x++){
	System.out.print(arr[x] + " ");
}
//输出结果
//1 3 5 7 9 
  1. 复制数组
//copyOf:把一个原有的数组内容复制到一个新数组中
int[] a={1,2,3};
//参数1:原数组   参数2:新数组的长度
int[] b=Arrays.copyOf(a, a.length);
System.out.println(Arrays.toString(b));
//输出结果
//[1, 2, 3]

数组结构优缺点
优点:

  1. 查询速度快
  2. 遍历数组方便

缺点:

  1. 数组大小固定,无法扩容
  2. 只能存储同一种类型的数据
  3. 添加,删除操作慢,因为要移动其他元素

数组的应用场景

  • 数组排序(冒泡、选择、插入排序)
  • 元素查找(二分查找)
  • 杨辉三角,九九乘法表(二维)
  • 数据大小确定,并且对数据操作简单

2.栈Stack


栈只允许在栈顶一端操作,栈底不允许操作。栈的特点是后进先出(先进后出)LIFO

//定义(数据类型为整型)
Stack<Integer> s = new Stack<>();
//基本方法
push(item)方法: 可以将item压入栈中。
pop()方法:可以移除栈顶的对象,并将其作为函数的返回值
peek()方法:查看栈顶对象
empty()方法:判断栈是否为空,为空则返回1,否则返回0
search(object object )方法:返回搜索的对象在栈中的位置

顺序栈SequenceStack
用一片连续存储空间(数组)来存储栈中的数据元素,这样的栈称为顺序栈。类似于顺序表。栈顶指示器top设在数组下标为最大的那一端,top随着插入或删除而变化。即当栈为空时,top=-1;其他时候,top为栈顶元素的索引号。
链栈
用链式存储结构存储的栈称为链栈,链栈通常用单链表来实现。它的结点结构与单链表的结构一样,都是由数据域data和引用域next两部分组成。由于链栈的操作只在一端进行(栈顶),一般将栈顶设在链表的头部,即将栈顶指示器指向链表的头部,所有对栈的数据元素的增加和删除操作都在链表头部进行。
java.util.Stack具有顺序栈的功能;
LinkedList类提供了在列表开始与结尾添加、删除和显示数据元素的方法,使用这些方法把一个LinkedList当做链栈使用。
栈的应用场景

  • 两个栈可以实现一个队列
//两个栈实现一个队列
class Queue<E>{
	private Stack<E> s1 = new Stack<>();
	private Stack<E> s2 = new Stack<>();
	//入队
	public void push(E val) {
		s1.push(val);
	}
	//出队
	public E poll() {
		while(s2.empty()){
			while(!s1.empty()) {
				s2.push(s1.peek());
				s1.pop();
			}
		}
		E val=s2.peek();
        s2.pop();
        return val;
	}
	//查看队头元素(与出队类似)
	//判断是否为空
	public boolean empty() {
		return s1.empty()&&s2.empty();
	}
}
  • 字符串倒序
//字符串倒序输出
Stack<> stack = new Stack<>();
    String str = "how are you";
    char[] cha = str.toCharArray();
    for(char c : cha){
        stack.push(c);
    }
    while(!stack.isEmpty()){
        System.out.print(stack.pop());
    }
//输出结果
//uoy era woh
  • 分隔符匹配
  • 由于先进后出的结构特性,栈常应用于实现递归功能方面的场景,如斐波那契数列
//分隔符匹配
//遇到左边分隔符了就push进栈,遇到右边分隔符了就pop出栈
public static boolean checkString(String string) {
	boolean matchFlag=true;
    Stack<Character> theStack=new Stack<Character>();
    char[] chs = string.toCharArray();
    for(int j=0; j<chs.length; j++) {
        char ch = chs[j];
        switch(ch) {
        case '{':
        case '[':
        case '(':
            theStack.push(ch);
            break;
        case '}':
        case ']':
        case ')':
            if(theStack.empty()) {
                matchFlag=false;
            } else {
                char chx=theStack.pop();
                if( (ch=='}' && chx!='{')||
                        (ch==']' && chx!='[')||
                        (ch==')' && chx!='(') ) {
                    matchFlag=false;
                }
            }
            break;
        default:
            break;
        }  //end switch
    }      //end for  loop
    //所有的字符都处理完毕,若此时栈中还有字符
    if(!theStack.empty()) {
        matchFlag=false;
    }
    return matchFlag;
}

3.队列Queue

队列和栈都是一种线性表。队列在一端添加元素,在另一端取出元素。队列的特点是先进先出(FIFO)。
LinkedList类实现了Queue接口,因此我们可以把LinkedList当成Queue来用

//定义队列(数据类型为整型)
Queue<Integer> s = new LinkedList<>();
//基本方法
add()offer():两个方法都是向队列中添加一个元素。不同的是如果在一个已满的队列
中再添加一个元素,调用add()方法会抛出一个IIIegaISlabEepeplian exception,而offer
会返回false,这样可以在程序中进行有效地判断

remove()poll():两个方法都是删除队列中的第一个元素。不同的是,当对一个空队列
进行操作时,remove()方法会抛出NoSuchElementException,而poll()会返回一个null值。

element()peek():两个方法都是查询队列的头部元素。与上述不同之处一样,element
方法在处理空队列时会抛出NoSuchElementException,而peek方法会返回null值

队列的应用场景

  • 两个队列实现一个栈
  • 循环链表(队列)
  • 多线程阻塞队列管理
  • 7
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值