Java数据结构和算法总结-数组、二分查找
前言:在平时开发中数组几乎是最基本也是最常用的数据类型,相比链表、二叉树等又简单很多,所以在学习数据和算法时用数组来作为一个起点再合适不过了。本篇博文的所有代码已上传 github ,对应工程的 array 模块,下载地址:https://github.com/lgliuwei/DataStructureStudy,项目工程为 IntelliJ IDEA 环境,童鞋不妨下载下来,参照着代码看博文岂不是效果更好~
首先介绍一下工程的目录结构和作用,本工程的各个模块之间以 Module 形式划分,每个 Module 大致对应一个专题(例如:链表对应工程中的 link),其中 libuitils 作为工具模块为其他的模块提供基础的工具类,例如输出语句的打印、字符串处理等等。

一、数组
俗话说磨刀不误砍柴工,为了后续的方便,先做一些准备工作,首先创建一个抽象类 BaseArray,包含的几个关键方法如下:
·initArrayByRandom(int size) :使用随机数生成一个数组。
·initArrayByRandomNoRepeat(int size):不重复的随机数生成一个数组。
·swap(int aIndex, int bIndex):交换数组中两个下标的值。
详细代码如下:
/**
* 数组基类
* Created by liuwei on 17/7/21.
*/
public abstract class BaseArray {
protected int[] mArray;
protected int mSize;
protected int mMaxSize;
public BaseArray(int maxSize){
mMaxSize = maxSize;
mArray = new int[mMaxSize];
mSize = 0;
}
public abstract int insert(int e) throws ArrayIndexOutOfBoundsException;
public abstract int delete(int e);
/**
* 随机数创建数组
* @param size
* @return
*/
public void initArrayByRandom(int size) throws ArrayIndexOutOfBoundsException {
if (size > mMaxSize) {
throw new ArrayIndexOutOfBoundsException("size不能大于数组的maxSize");
} else {
mSize = size;
for (int i = 0; i < size; i++) {
mArray[i] = getRandomInt(size);
}
}
}
/**
* 随机数创建数组(无重复)
* @param size
* @return
*/
public void initArrayByRandomNoRepeat(int size) throws ArrayIndexOutOfBoundsException {
if (size > mMaxSize) {
throw new ArrayIndexOutOfBoundsException("size不能大于数组的maxSize");
} else {
mSize = size;
int n = 0;
boolean noRepeat;
while (n < mSize) {
noRepeat = true;
int temp = getRandomInt(mSize * 10);
for (int i = 0; i < n; i++) {
if (temp == mArray[i]) {
noRepeat = false;
break;
}
}
if (noRepeat) {
mArray[n] = temp;
n++;
}
} }
}
public void initArray(int[] array) {
mSize = array.length;
for (int i = 0; i < mSize; i++) {
mArray[i] = array[i];
}
}
public int size(){
return mSize;
}
/**
* 获取一个随机整数
* @return
*/
public int getRandomInt(int bounder){
return new Random().nextInt(bounder);
}
public void display(){
for (int i = 0; i < mSize; i++) {
print(mArray[i] + ", ");
}
println("");
}
protected void swap(int aIndex, int bIndex) {
int temp = mArray[aIndex];
mArray[aIndex] = mArray[bIndex];
mArray[bIndex] = temp;
}
protected void print(Object o){
Logger.print(o);
}
protected void println(Object o){
Logger.println(o);
}
}
看到这个类比较长也不要害怕,它里面只是包含一些工具性质的方法,目的是为我们提供方便,使我们在后续的二分查找和排序中可以更加专注于算法之中。
接着通过继承 BaseArray 创建一个有序数组类 OrderedArray ,普通的插入对于数组来说再简单不过了,直接往对应的下标中赋值即可,就不多说了,这里为创建的实体数组添加一个有序插入(正序)的方法,初步想了一下有序插入大致需要三步:
1、从数组的0下标开始往后找,直到发现大于带插入的值时停下,记录下标。
2、从数组的最后一个下标开始依次后移一位,直到第一步中记录的下标。
3、将带插入的值赋给第一步中纪律的下标。

详细代码如下:
/**
* 有序插入
*/
@Override
public int insert(int e) throws ArrayIndexOutOfBoundsException {
if (mSize == mMaxSize) {
throw new ArrayIndexOutOfBoundsException("数组已经满了");
}
int i;
for (i = 0; i < mSize; i++) {
if (e < mArray[i]) break;
}
for (int j = mSize; j > i; j--) {
mArray[j] = mArray[j-1];
}
mArray[i] = e;
mSize++;
return i;
}
二、线性查找
如果我们想从一个有序数组中查找一个元素有两种方法,线性查找和二分查找,线性查找就是最最常规的方法,从数组的0下标开始依次往后查找,直到找到要查找的元素,则查找成功,如果在数组中不存在带查找的元素,因为是有序数组,我们只需找到比待查元素大时即可退出。
线性查找详细代码如下:
/**
* 线性查找
* @param e
* @return
*/
public int findByLiner(int e) {
for(int i = 0; i < mSize; i++) {
if (e == mArray[i]) {
return i;
} else if (mSize > (i + 1) &&e > mArray[i] && e < mArray[i + 1]) {
return -1;
}
}
return -1;
}
线性查找比较简单,这里不过过多分析,很容易我们就能看出来线性查找的平均比较次数是数组元素个数的一半,所花费的时间与元素个数(假设是N)的一半成正比,在算法中描述时间复杂度是我们通常忽略常数,习惯性用大O表示法,所以线性查找的时间复杂度表示为:O(N)。
三、二分查找
二分查找类似于我们朋友聚会喝酒时玩的猜字游戏,游戏中,通常会给出一个范围例如0-100,然后由一方从中默默挑出一个字让你来猜,你猜的时候他会告诉你是否猜中,或者比他挑的字大或小。为了尽快的猜中,我们会选择首先从中间开始猜,根据对方的提示我们来选择偏大的一半还是偏小的一半然后再从新范围的一半开始猜,这样很快就能猜中答案。
具体的算法思路如下(假设数组下标范围是0-N):
1、首先定义两个下标边界变量lowBounder=0,highBounder=N-1
2、让当前下标为lowBounder和highBounder的中间与待查找的元素比较:
·如果相等,则查找成功。
·如果小于待查找元素,则将lowBounder赋值为当前下标+1。
·如果大于带查找元素,则将hightBounder赋值为当前下标-1。
·如果此过程发现lowBounder大于highBounder,则表示未找到。
3、循环执行第二步。
详细代码如下:
/**
* 二分查找
* @param e
* @return
*/
public int findByHalf(int e) {
int lowIndex = 0;
int highIndex = mSize - 1;
int currentIndex;
while(true){
currentIndex = (lowIndex + highIndex) / 2;
if (e == mArray[currentIndex]) {
return currentIndex;
} else if (lowIndex >= highIndex) {
return -1;
} else if (e > mArray[currentIndex]) {
lowIndex = currentIndex + 1;
} else {
highIndex = currentIndex - 1;
}
}
}
单从思路我们就可以分析出二分查找的平均查找时间要比线性查找快的多。
它的时间复杂度为:O(logN)。
Java数据结构和算法总结-数组、二分查找的更多相关文章
- Java数据结构和算法的数组
阵列的功能: 1.固定大小 2.相同的数据类型 3. 4.数据项可反复 Java数据类型:基本类型(int和double)和对象类型.在很多编程语言中.数组也是基本类型.但在Java中把它们当作对象来 ...
- Java数据结构和算法之数组与简单排序
一.数组于简单排序 数组 数组(array)是相同类型变量的集合,可以使用共同的名字引用它.数组可被定义为任何类型,可以是一维或多维.数组中的一个特别要素是通过下标来访问它.数组提供了一种将有联系的信 ...
- golang数据结构和算法之BinarySearch二分查找法
基础语法差不多了, 就需要系统的撸一下数据结构和算法了. 没找到合适的书, 就参考github项目: https://github.com/floyernick/Data-Structures-and ...
- Java数据结构和算法 - 数组
Q: 数组的创建? A: Java中有两种数据类型,基本类型和对象类型,在许多编程语言中(甚至面向对象语言C++),数组也是基本类型.但在Java中把数组当做对象来看.因此在创建数组时,必须使用new ...
- Python 迭代器&生成器,装饰器,递归,算法基础:二分查找、二维数组转换,正则表达式,作业:计算器开发
本节大纲 迭代器&生成器 装饰器 基本装饰器 多参数装饰器 递归 算法基础:二分查找.二维数组转换 正则表达式 常用模块学习 作业:计算器开发 实现加减乘除及拓号优先级解析 用户输入 1 - ...
- Java数据结构和算法 - 二叉树
前言 数据结构可划分为线性结构.树型结构和图型结构三大类.前面几篇讨论了数组.栈和队列.链表都是线性结构.树型结构中每个结点只允许有一个直接前驱结点,但允许有一个以上直接后驱结点.树型结构有树和二叉树 ...
- Java数据结构和算法 - 递归
三角数字 Q: 什么是三角数字? A: 据说一群在毕达哥拉斯领导下工作的古希腊的数学家,发现了在数学序列1,3,6,10,15,21,……中有一种奇特的联系.这个数列中的第N项是由第N-1项加N得到的 ...
- 数据结构和算法(Golang实现)(29)查找算法-2-3树和左倾红黑树
某些教程不区分普通红黑树和左倾红黑树的区别,直接将左倾红黑树拿来教学,并且称其为红黑树,因为左倾红黑树与普通的红黑树相比,实现起来较为简单,容易教学.在这里,我们区分开左倾红黑树和普通红黑树. 红黑树 ...
- Java数据结构和算法(十四)——堆
在Java数据结构和算法(五)——队列中我们介绍了优先级队列,优先级队列是一种抽象数据类型(ADT),它提供了删除最大(或最小)关键字值的数据项的方法,插入数据项的方法,优先级队列可以用有序数组来实现 ...
随机推荐
- 基于FPGA的Sobel边缘检测的实现
前面我们实现了使用PC端上位机串口发送图像数据到VGA显示,通过MATLAB处理的图像数据直接是灰度图像,后面我们在此基础上修改,从而实现,基于FPGA的动态图片的Sobel边缘检测.中值滤波.Can ...
- selenium元素定位不到之iframe
我们在使用selenium的18中定位方式的时候,有时会遇到定位不上的问题,今天我们就来说说导致定位不上的其中一个原因---iframe 问题描述:通过firebug查询到相应元素的id或name等, ...
- 基于CAS的SSO(单点登录)实例
第一步 部署CAS-Server(服务端) 1.从CAS官方网站(http://developer.jasig.org/cas/)下载最新版本的CAS-Server(当前最新版本cas-server- ...
- poj 1948二维01背包
题意:给出不多于40个小棍的长度,求出用所有小棍组成的三角形的最大面积. 思路:三角形3边求面积,海伦公式:p=(a+b+c)/2;S=p*(p-a)*(p-b)*(p-c);因为最大周长为1600 ...
- Java 循环和函数(方法)
1 for循环嵌套 简而言之,就是一个for循环语句里面,还有一个for循环语句. 外层循环,每循环一次,内层循环,循环一周. 示例 package java003; /** * 2017/9/1. ...
- 【1414软工助教】团队作业2——需求分析&原型设计 得分榜
题目 团队作业2--需求分析&原型设计 作业提交情况情况 本次作业所有团队都按时提交作业. 往期成绩 个人作业1:四则运算控制台 结对项目1:GUI 个人作业2:案例分析 结对项目2:单元测试 ...
- 201521123026 《Java程序设计》第三周学习总结
1. 本章学习总结 初学面向对象,会学习到很多碎片化的概念与知识.尝试学会使用思维导图将这些碎片化的概念.知识组织起来.请使用纸笔或者下面的工具画出本周学习到的知识点.截图或者拍照上传. 2. 书面作 ...
- 201521123010 《Java程序设计》第14周学习总结
1. 本周学习总结 1.1 以你喜欢的方式(思维导图或其他)归纳总结多数据库相关内容. 2. 书面作业 1. MySQL数据库基本操作 建立数据库,将自己的姓名.学号作为一条记录插入.(截图,需出现自 ...
- 201521123068 《java程序设计》 第11周学习总结
1. 本周学习总结 1.1 以你喜欢的方式(思维导图或其他)归纳总结多线程相关内容. 多线程的冲突:同时运行的线程需要访问共享数据(临界资源) 多线程的互斥访问:两个或两个以上的线程需要同时对同一数据 ...
- 201521123102 《Java程序设计》第9周学习总结
1. 本周学习总结 1.1 以你喜欢的方式(思维导图或其他)归纳总结异常相关内容. 2.书面作业 1.常用异常 题目5-1 1.2 自己以前编写的代码中经常出现什么异常.需要捕获吗(为什么)?应如何避 ...