马上要自考了,其中有一门数据结构,好久没复习,忘得差不多了,今天从头开始,顺便记一下笔记。我看的是Java数据结构和算法这本书,所以这里的数据结构和算法全都用Java语言描述。每篇笔记都会附上随书的Applet演示程序,有算法看不明白的,可以下载Applet运行起来(直接打开html文件即可),可以很容易地看清楚算法的每一步。
二分查找法和线性查找法
二分查找法是一种比普通线性查找快得多的查找算法,但只适用于有序集合当中。拿
升序排序后的
整型数组来说,二分法具体的实现原理是:先把
待查找数a与
数组中间的那个数x对比,如果相等,直接返回x的索引;如果a大于x,则排除掉
数组的前面一半(包括x),接着拿a与
剩下一半数组中间的那个数x对比,如果相等,直接返回x的索引;如果a小于x,则排除掉数组
后面一半的后面一半……如此循环直到找到目标。
普通的
线性查找法是从数组的第一个数开始对比,接着是第二个,第三个……直到找到目标。
大O表示法
大O表示法是一种粗略试题算法效率的方法。了解大O表示法之前先看一组公式:
无序数组的插入是与数组中数据项个数无关的算法,由于插入时不必考虑排序,新数据项总是被放在下一个有空的地方。我们可以说向一个无序数组中插入一个数据项的时间T是一个
常量K(K值与cpu运行速度、编译程序生成程序代码的效率等有关),得出:
T = K
在数据项的线性查找中,
最好的情况下比较次数只有1次(数组第1个数据项就是所要查找目标的情况);
最坏的情况下比较次数有N(数组长度)次(数组最后一个数据项是查找目标)。平均次数为N/2次,搜索时间T与N/2成正比,也就是与N成正比:
T = K*N
二分查找法……先反过来思考一个问题:只给5次比较机会,能搜索到目标的最大范围数组长度是多少?1次能比较2个,2次能比较4个,3次能比较8个,4次16个,5次32个。设
数组长度为N,
比较次数为X,N是2的X次方,也就是说X是以2为底N的对数即log2(N)。由此得出二分查找法在最坏情况下花费的时间T为比较次数log2(N)乘以单次比较所花费的时间K,即:
T = K*log2(N)
也就是T与log2(N)成正比。由于任何对数都和其他对数成比例,我们也可以说T与log(N)(以10为底N的对数)成正比,即:
T = K*log(N)
大O表示法同上面的公式比较类似,但它省去了常数K。因为比较算法时不需要在乎硬件设备等。大O表示法使用大写字母O,可以使用大O表示法来描述线性查找使用了O(N)级时间,二分查找使用了O(log N)级时间,向一个无序数组插入数据使用了O(1)(或常数)级时间。
无序数组和有序数组
下面是两个简单数组类,其中无序数组的add方法直接向成员array中插值,时间复杂度用大O表示法表示为O(1);有序数组的add方法平均要经过N/2次比较,不考虑插入值之前向后移动数组所花时间(当然这很花时间),时间复杂度为O(N);无序数组的delete方法首先要调用私有的find方法,这里find方法使用线性查找法,时间复杂度为O(N);有序数组的delete方法所调用的binarySearch是二分查找法,时间复杂度为O(log N)。
结论是:
1、无序数组插值效率比有序数组要高得多(有序数组插值时除了比较数据还要移动数组);
2、有序数组删除数据的效率比无序数组高(两种数组在删除数据时都要移动数组,只在查找数据的算法上有区别)。
无序数组类:
package dsaa.array;
/**
* @(#)SortedArray.java 2008-12-24 下午06:36:22
*
* @author Qiu Maoyuan
* Unsorted Array
*/
public class UnsortedArray {
private int[] array;
private int size = 0;
public UnsortedArray(int initialCapacity){
this.array = new int[initialCapacity];
}
public UnsortedArray(){
this(10);
}
public void add(int number){
ensureCapacity();
array[size++] = number;
}
public int get(int index){
if(index>=size)
throw new IndexOutOfBoundsException();
return array[index];
}
public boolean delete(int value){
int index = find(value);
if(index==size)
return false;
moveFrontwards(index);
size--;
return true;
}
private void ensureCapacity() {
if(size==array.length){
int[] newArray = new int[size * 3 / 2 + 1];
System.arraycopy(array, 0, newArray, 0, size);
array = newArray;
}
}
private int find(int value){
int i = 0;
while(i<size && array[i]!=value) i++;
return i;
}
private void moveFrontwards(int startingIndex){
for(int i=startingIndex; i<size-1; i++)
array[i] = array[i+1];
}
}
有序数组类:
package dsaa.array;
/**
* @(#)SortedArray.java 2008-12-24 下午06:36:22
*
* @author Qiu Maoyuan
* Sorted Array
*/
public class SortedArray {
private int[] array;
private int size = 0;
public SortedArray(int initialCapacity){
this.array = new int[initialCapacity];
}
public SortedArray(){
this(10);
}
public void add(int value){
if(size==0){
array[0] = value;
size++;
return;
}
ensureCapacity();
for(int i=0; i<size+1; i++){
if(value<array[i]){
moveBackwards(i);
array[i] = value;
size++;
return;
}
}
array[size] = value;
size++;
}
public int get(int index){
if(index>=size)
throw new IndexOutOfBoundsException();
return array[index];
}
public boolean delete(int value){
int index = binarySearch(value);
if(index==size)
return false;
moveFrontwards(index);
size--;
return true;
}
public int getSize(){
return this.size;
}
private void ensureCapacity() {
if(size==array.length){
int[] newArray = new int[size * 3 / 2 + 1];
System.arraycopy(array, 0, newArray, 0, size);
array = newArray;
}
}
private void moveBackwards(int startingIndex) {
for(int j=size; j>startingIndex; j--){
array[j] = array[j-1];
}
}
private void moveFrontwards(int startingIndex){
for(int i=startingIndex; i<size-1; i++)
array[i] = array[i+1];
}
private int binarySearch(int target){
if(size==0) return size;
int currentIndex;
int lowerBound = 0;
int upperBound = size - 1;
while(true){
currentIndex = (lowerBound + upperBound) / 2;
int currentValue = array[currentIndex];
if(currentValue==target)
break;
else if(currentValue<target){
lowerBound = currentIndex + 1;
}else{
upperBound = currentIndex - 1;
}
if(lowerBound>=upperBound) return size;
}
return currentIndex;
}
}
分享到:
相关推荐
二分法查找 *进行二分法查找的前提是数组已有序 *查找范围的上下界
Java数组练习作业按逆序存放并输出二分法将一个数据插入到该数组二维数组对角线之和 在本资源中,我们将介绍Java数组的相关知识点,包括数组的逆序存放和输出、二分法插入数据到数组、计算二维数组对角线之和等。 ...
数据结构学习(C++)——递归 双向链表 水波算法实例 算法 平摊分析 算法表达中的抽象机制 随机数算法 台阶问题 通用冒泡排序 图遍历应用 图象扭曲算法 图象增强 五子棋算法 希 尔 排 序 线性链式结构总结 循环链表 ...
数据结构学习(C++)——递归 双向链表 水波算法实例 算法 平摊分析 算法表达中的抽象机制 随机数算法 台阶问题 通用冒泡排序 图遍历应用 图象扭曲算法 图象增强 五子棋算法 希 尔 排 序 线性链式结构总结 循环链表 ...
数组的查找——二分法查找 也称拆半查找法,是一种高效的查找方法,前提条件是数组元素必须已经按升序排好序。 如在有序一维数组[-10 , 3 , 4 , 11 , 22 , 43 , 49 , 56 , 90 , 90]中: -10 3 4 11 22 43 49 56 90 ...
题目: 编程实现找出一组数的最大值和次大值 要求: 用二分法的策略实现; (2)写出实验报告。 一、 需求分析: 1、输入要输入数组元素的个数,为数组... 3、利用二分法找出数组中的最大值和次大值; 4、输出结果;
本文将深入探讨Java中的冒泡排序、插入排序以及二分法查找这三种基础算法,这些都是面试时经常会被问到的技术点。 首先,让我们从冒泡排序开始。冒泡排序是一种简单直观的排序算法,它重复地遍历待排序的数列,一次...
### Java数据结构与算法、树、图:深入解析与学习指南 #### 1. 数据结构与算法概览 数据结构和算法是计算机科学的核心组成部分,它们对于理解和解决复杂问题至关重要。数据结构涉及到如何组织和存储数据,而算法则...
Java 数据结构测试题涉及到多个Java编程基础和设计概念,包括数据结构、软件设计工具、多分支语句(switch语句)、继承与多态、自定义表格模型以及并发控制。以下是这些知识点的详细解释: 1. **二分法查找**: - ...
根据给定的信息,本文将详细解释“二分法求数组和”的实现原理与方法,同时结合递归思想进行深入探讨。 ### 一、二分法求数组和概述 在计算机科学中,二分法通常被应用于有序数组的搜索问题上。然而,在本例中,...
快速排序和二分法查找是数据结构中两个非常重要的概念,它们都是解决实际问题的重要工具。在本文中,我们将详细介绍快速排序和二分法查找的原理、实现和应用。 快速排序 快速排序(Quicksort)是一种基于比较的...
本文将深入探讨Java中常用的八大排序算法以及二分法查找,旨在帮助算法爱好者和开发人员提升解决问题的能力。 首先,让我们来看Java中的八大排序算法: 1. 冒泡排序:这是一种简单的排序方法,通过重复遍历待排序...
本资料包聚焦于"Java常用排序算法"和"程序员必须掌握的8大排序算法",并深入探讨了"二分法查找"这一高效搜索技术。 首先,我们来看八大排序算法。这些算法包括: 1. **冒泡排序**:最简单的排序方法,通过不断交换...
### 图解数据结构:二分法查找法 #### 一、引言 在计算机科学领域,数据结构与算法是核心的基础知识。其中,查找算法作为数据处理中的关键环节,其效率直接影响着系统的性能。二分查找法(Binary Search),作为一...
在编程领域,排序算法是计算机科学的基础之一,它在数据处理和分析中起着至关重要的作用。本篇文章将深入探讨如何使用JavaScript实现十大经典排序算法,帮助开发者更好地理解和运用这些算法。 1. 冒泡排序(Bubble ...
计算机二分法的算法步骤-五大常用算法之一:分治算法,算法数据结构 五大常用算法 分治算法是一种常用的算法设计方法,它将一个规模为n的问题P分解成k个规模较小的子问题,这些子问题相互独立,并且与原来的问题...
数据结构及算法编程 ☆ “二分法”求二元方程的解 ☆ Bresenham高效画线...☆ 数据结构学习(C++)——递归 ☆ 双向链表 ☆ 水波算法实例 ☆ 算法 平摊分析 ☆ 算法表达中的抽象机制 ☆ 算法综合知识 ☆ 随机数算法