Data Structures and Algorithms Week2: Binary search, Sorting and Linked list
Binary search 二分查找
Simple in principle but Hard in practice
原理简单但是难以实践
- “Professional programmers had a couple of hours to convert the above description (binary search) into a program in the language of their choice …
“专业程序员有几个小时的时间将上述描述(二分查找)转换为他们选择的语言编写的程序… - At the end of the specified time, almost all the programmers reported that they had correct code for the task …
“在指定的时间结束时,几乎所有程序员都报告说他们已经为该任务编写了正确的代码… - ninety percent of the programmers found bugs in their programs.”
“90%的程序员在他们的程序中发现了错误。”
Principle 原则
Efficient search in a sequence. 在序列中高效搜索。
Requirement (pre-condition): The sequence must be ordered.
要求(前提条件):序列必须 有序。
This version is by Prof. Niklaus Wirth
此版本由 Niklaus Wirth 教授提供
It is surprisingly efficient and easy to show to be correct
它非常高效,而且很容易证明其正确性
Pre-condition 前置条件
The sequence in the array must be ordered.
数组中的序列必须是有序的。
T a[N]; (* a[0] to a[N-1] *)/* T is any type for which < == ... defined, such as int *//* precondition: 0 <=size <= N & (∀i: 0 < i < size: a[i-1] <=a[i]) */Invariant 不变式

/* precondition: 0 <=size <= N &(∀i: 0 < i < size: a[i-1] <= a[i]) */int left, right; /* 0 ... size *//* invariant: precondition & a[0 ... left–1] < x & // all before left are less than x a[right ... size-1] >= x*/all from right up to size-1 are at least as big as x 所有从 right 到 size-1 的元素都至少和 x 一样大
Initially

left = 0; right = size;/* makes empty segments */Finally

Outline of loop 循环概述

left = 0; right = size;/* invariant*/while (left != right) { /* invariant & left != right */ body /* invariant */}/* (invariant & left == right) => postcondition*/Body: Inspect mid element 主体:检查中间元素

int mid;…mid = (left + right) / 2;a[mid] < x ? left = mid +1;a[mid] >= x ? right = mid;Body: Inspect mid element 主体:检查mid元素

left = 0; right = size;while (left != right) { /* invariant and left != right */ mid = (left + right) / 2; if (a[mid] < x) left = mid + 1; else right = mid; /* invariant */}At the end

left == right and so found if a[left] == x, (or a[right] == x, since left == right)

left == right and so found if a[left] == x (or a[right] == x) what if right never moved. All elements < x, as in picture? Correct? No: we need to be sure that:
0 <= left < sizeThe algorithm

left = 0; right = size;while (left != right) { /* invariant and left != right */ mid = (left + right) / 2; if (a[mid] < x) left = mid + 1; else right = mid; /* invariant */}found = (left != size) && (a[left] == x);Proving that it terminates: Bound
证明它终止:界限

Length of grey area is reduced each time, so bound is right - left
Each time the body is carried out:
either left gets bigger, or
right gets smaller
So eventually left == right and it terminates.
O(?)

Length of grey area is halved each time, so the time complexity of the binary search algorithm is?
Efficiency 效率
“Not found” takes more iterations* than versions of binary search that terminate as soon as an x is found.
“未找到“需要比立即在找到x时终止的二分查找版本更多的迭代。
However, each iteration requires only one access of the array; so more efficient.
然而,每次迭代只需要访问数组一次;因此更高效。
Useful consequence(结果): finds first (lowest-indexed) x
Thinking question: How many more iterations?
Just one more thing …
There is still a problem!
left + right might lead to numeric overflow 数值溢出;
This can be avoided by using a bit of algebra 代数:
The expression on the right side will not overflow, since its value never exceeds that of right.
So finally …
left = 0; right = size;while (left != right) { /* invariant and left != right */ mid = left + (right - left) / 2; if (a[mid] < x) left = mid + 1; else right = mid; /* invariant */}found = (left != size) && (a[left] == x);Summary
After studying the material of this lecture and the associated parts of the textbook and attempting the exercises, you should be able to:
Explain what is meant by a binary search
Understand the precondition of a binary search.
Correctly implement a binary search given a suitable loop invariant.
给出合适的循环不变式,正确实现二分查找。
Practical exercise 实践练习
- Problem:
Input non-negative integers , which are monotonically non-decreasing. Then perform queries. For each query, an integer is given. You are required to output the index of the first occurrence of this number q in the sequence. If it is not found, output -1. - 题目:
输入 个非负整数 ,它们按单调不降顺序排列。然后进行 次查询。每次查询给定一个整数 。要求输出该数字 q 在序列中第一次出现的下标;若未找到则输出 -1。
- Input:
- The first line contains two integers n and m, representing the number of integers and the number of queries.
第一行包含两个整数 n 和 m,分别表示整数个数和查询次数。 - The second line contains n integers, representing the numbers to be queried.
第二行包含 n 个整数,表示待查询的有序序列。 - The third line contains m integers, representing the indices of the numbers to be queried.
第三行包含 m 个整数,表示要查询的目标数值。 - Example:
- The first line contains two integers n and m, representing the number of integers and the number of queries.
11 21 3 3 5 7 9 11 13 15 153 12find q[j] 3 at 1find q[j] 12 at -1Sorting
Content
- ‘Straight’ sorting 直接排序
- Why straight sorting is not very good
为什么直接排序并不理想
- Why straight sorting is not very good
- Quicksort 快速排序
- Who discovered it
是谁发现了它 - Why is it so quick
为什么它这么快 - When it is ‘Slowsort’
什么时候它会变成“慢排序”
- Who discovered it
Typical scenario 典型场景
- I sort coursework submissions manually into alphabetical order of author.
我手动把课程作业按作者字母顺序排序。- I took 30 minutes to sort 25 students.
我给 25 位学生排序花了 30 分钟。 - How long do you estimate the sorting for 50 students will take him?
你估计给 50 位学生排序要花多久?
- I took 30 minutes to sort 25 students.
- Most sorting algorithms are , that is, time is proportional to number of records squared, so if n doubles the sorting takes 4 times as long
大多数排序算法是 ,也就是时间与记录数的平方成正比,所以当 n 翻倍时,排序时间会变为 4 倍。
Insertion Sort 插入排序
This ‘straight’ sorting method works by inserting the next item of the unsorted stretch of a sequence into the already-sorted first stretch of the sequence.
这种“直接”排序方法的思路是:把未排序区间的下一个元素插入到前面已经排好序的区间中。

// post a[0..size-1] is ascendingvoid insertionSort(int [ ] a) { int i= 1; int x; int j; while (i < a.length) { // a[0..i-1] is ascending // insert value at a[i] into correct position in a[0..i-1] j= i; x= a[i]; // x is the value originally at a[i] while (j != 0 && a[j-1] > x) { // 'budge up' values that are bigger than the one at a[i] a[j]= a[j-1]; j--; } // j == 0 OR a[j-1] <= x // 'drop in' x, the value that was at a[j] a[j]= x; i++; // advance to insert next value } // i >= a.length}Performance of Insertion Sort 插入排序的性能
- The insertion sort has a while loop iterating through all n elements of the sequence.
插入排序有一个 while 循环 会遍历序列中全部 n 个元素。 - Within that it has another while loop iterating though all the elements before the one to be inserted
在此循环内部,还有另一个 while 循环,遍历待插入元素 之前 的所有元素。 - So the performance is proportional to n2.
因此其性能与 n2 成正比。
Simple sorting methods 简单排序方法
- Simple (naive) sorting methods such as selection sort, insertion sort and ‘bubble sort’ are O(n2) – that means they take time proportional to the size of the sequence squared.
简单(朴素)排序方法,如 选择排序、插入排序和冒泡排序 的复杂度是 O(n2),即耗时与序列长度的平方成正比。 - They only move values a short distance on each pass.
它们每一趟只会把元素移动 很短的距离。
Quicksort: discoverer 快速排序:发现者
- He called it ‘Quicksort’ because it is dramatically quick.
他将其命名为“Quicksort(快速排序)”,因为它的速度非常快。 - Machine translation: ‘To assist in efficient look-up of words in a dictionary, he discovered the well-known sorting algorithm Quicksort’.
机翻示例:“为了高效查找字典中的单词,他发现了著名的排序算法 Quicksort。”
Professor Sir Tony Hoare FRS
英国皇家学会会士 Tony Hoare 爵士教授
C.A.R. Hoare, “Quicksort”, The Computer J.,Vol. 5, No. 1, Apr. 1962, pp. 10-15.
Quicksort 快速排序
- Works in place –
- no extra storage space needed.
不需要额外存储空间。
- no extra storage space needed.
- Not stable –
- does not preserve the order of records with same keys is dramatically fast!
不保证相同关键字记录的相对顺序,但速度非常快!
- does not preserve the order of records with same keys is dramatically fast!
Inspiration comes from 灵感来源
- If we had values that we knew to be in completely the wrong order, we could reverse the order in n/2 steps:
如果我们知道一组值处于完全相反的顺序,就可以在 n/2 步内把它们反转: - start at the ends and swap elements until we reach the middle.
从两端开始交换元素,直到扫描到中间。 - We don’t usually have completely mis-ordered lists, but it gives the idea for Quicksort.
实际中序列通常不是完全反序,但这给了快速排序设计思路。
Partitioning 划分
- To sort array a:
对数组 a 进行排序:- Pick any item at random, call it x (the pivot)
随机选取一个元素,记为 x(即主元 pivot) - Scan array from left until an item ai > x is found
从左向右扫描,直到找到一个 ai > x 的元素 - Scan array from right until an item aj < x is found
从右向左扫描,直到找到一个 aj < x 的元素 - Now exchange the two items and continue this ‘scan and swap’ process until the two scans meet somewhere in the middle of the array.
交换这两个元素,并持续执行这种“扫描并交换”的过程,直到两端扫描在数组中间相遇。
- Pick any item at random, call it x (the pivot)
- actually we use ai >= x and ai <= x to simplify loop guards(循环约束)
- The result is that the array is now ‘partitioned’ into a
结果是数组被“划分”为:- left part with keys all less than or equal to x
左侧部分:键值都小于等于 x - and a right part with keys all greater than or equal to x.
右侧部分:键值都大于等于 x。
- left part with keys all less than or equal to x
- These two parts can now be separately sorted – by Quicksort!
这两个部分接下来可以分别继续用快速排序处理!
void quicksort(int [ ] a, int low, int high) { int i= low, j= high, temp; int pivot= a[(low + high) / 2]; while (i <= j) { while (a[i] < pivot) i++; while (a[j] > pivot) j--; // forall k :low ..i -1: a[k] < pivot && forall k: j+1 .. high: a[k] > pivot && // a[i] >= pivot && a[j] <= pivot if (i <= j) { temp= a[i]; a[i]= a[j]; a[j]= temp; i++; j--; } }…}Now partition the partitions 继续划分子区间
- We have only partitioned, but we wish to sort.
我们目前只是完成了划分,目标是最终排序。 - Repeat the partitioning process on each of the partitions until left with a partition of only one element
对每个子区间重复执行划分,直到每个区间只剩一个元素。 - method quicksort activates itself recursively.
quicksort 方法会递归调用自身。
Quicksort 快速排序
void quicksort(int [ ] a, int low, int high) { int i= low, j= high, temp; int pivot= a[(low + high) / 2]; while (i < j) { while (a[i] < pivot) i++; while (a[j] > pivot) j--; if (i <= j) { temp= a[i]; a[i]= a[j]; a[j]= temp; i++; j--; } } if (low < j) quicksort(a,low, j); // recursive call if (i < high) quicksort(a, i, high); // recursive call}recursive 递归的
recursion 递归
Time complexity:
时间复杂度:
average:
平均:
worst:
最坏:
- i, j = position
i、j 是位置指针 - pivot is data, compare with others
pivot 是基准值,用它与其他元素比较 - right place: move on / wrong place: i, j stop, swap
位置正确则继续移动;位置错误时 i、j 停下并交换 - left right
左右两侧同步推进
Getting it started 开始调用
void sort(int [ ] a) { quicksort(a, 0, a.length-1);}Analysis of Quicksort 快速排序分析
- Average performance is
平均性能为 。 - Worst case:
最坏情况:- when data is already ordered, performance becomes unless middle element chosen as pivot.
当数据已接近有序时,若主元选择不佳,性能会退化到 。 - Worst-case performance is improved by choosing middle element as pivot
选择中间元素作为主元可改善最坏情况表现。
- when data is already ordered, performance becomes unless middle element chosen as pivot.
Comparison of sorting 排序比较
- ‘Straight’, ‘naive’ sorts ——
“直接/朴素”排序 —— - ‘logarithmic sorts’ (Quicksort) ——
“对数级”排序(Quicksort)—— - Bubble sort is the slowest sorting method known! (but has a catchy name)
冒泡排序 是已知最慢的常见排序方法之一!(但名字很好记) - Quicksort is one of the fastest.
快速排序 是最快的方法之一。
Actual numbers 具体数值
| (Bubblesort) | (Quicksort) | |
|---|---|---|
| 32 | 1,024 | 160 |
| 64 | 4,096 | 384 |
| 128 | 16,384 | 896 |
| 256 | 65,536 | 2,048 |
| 512 | 262,144 | 4,608 |
| 1,024 | 1,048,576 | 10,240 |
References 参考资料
C.A.R. Hoare, “Quicksort”, The Computer J., Vol. 5, No. 1, Apr. 1962, pp. 10-15. https://portal.acm.org/citation.cfm?id=366644
The Art of Computer Programming, Vol. 3 – Sorting and Searching ISBN 0201896850 Author Donald E Knuth Addison-Wesley
Zonnon Report Zonnon Language Report Jürg Gutknecht Editors: Brian Kirk and David Lightfoot July 2009 https://www.zonnon.ethz.ch/language/report.html
From the Communications of the ACM
Summary 总结
- After studying the material of this week and attempting the exercises, you should be able to:
学习本周内容并完成练习后,你应该能够:- understand why straight sorting techniques are not very efficient
理解为什么直接排序技术效率不高 - understand the principle of Quicksort
理解 Quicksort 的基本原理 - know the efficiency of Quicksort (average case)
掌握 Quicksort 的平均情况效率 - know worst-case performance of Quicksort
了解 Quicksort 的最坏情况性能
- understand why straight sorting techniques are not very efficient
Better Quicksort (Three-way QuickSort) 更优快速排序(三路快排)
public void quickSort3Way(int[] arr, int low, int high) { if (low >= high) return; int lt = low, i = low + 1, gt = high; int pivot = arr[low]; while (i <= gt) { if (arr[i] < pivot) { swap(arr, lt++, i++); } else if (arr[i] > pivot) { swap(arr, i, gt--); } else { i++; } } quickSort3Way(arr, low, lt - 1); quickSort3Way(arr, gt + 1, high);}Concurrent Quicksort 并发快速排序
activity PQuickSort(L, R: integer);var i, j: integer; w, x: ElementOfArray;begin i := L; j := R; x := MyArray[(L + R) div 2]; repeat while MyArray[i] < x do i := i + 1 end; while x < MyArray[j] do j := j - 1 end; if i <= j then w := MyArray[i]; MyArray[i] := MyArray[j]; MyArray[j] := w; i := i + 1; j := j - 1; end until i > j; if L < j then new PQuickSort(L, j) end; (*new activity – runs in parallel *) if i < R then new PQuickSort(i, R) end; (*new activity – runs in parallel *)end QuickSort;
procedure ConcurrentQS;begin(* now instantiate the first activity with initial parameters *) new PQuickSort(integer(0), integer(MAX_SIZE - 1));end ConcurrentQS;Linked list 链表
Content 内容
- Implementation and efficiency of ArrayList
ArrayList 的实现与效率 - Linked lists
链表 - Insertion into, and deletion from, linked lists.
链表的插入与删除 - A linked list abstract data type (ADT)
链表抽象数据类型(ADT) - Recap of inner classes
回顾 inner classes(内部类) - Iterators 迭代器
Arraylist under the bonnet ArrayList 底层原理
- Defined in the JDK already
在 JDK 中已经定义
public class ArrayList<E> extends AbstractList<E> implements List<E>, RandomAccess, Cloneable, java.io.Serializable{ @java.io.Serial private static final long serialVersionUID = 8683452581122892189L;
/** * Default initial capacity. */ private static final int DEFAULT_CAPACITY = 10;
/** * Shared empty array instance used for empty instances. */ private static final Object[] EMPTY_ELEMENTDATA = {};
/** * Shared empty array instance used for default sized empty instances. We * distinguish this from EMPTY_ELEMENTDATA to know how much to inflate when * first element is added. */ private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
/** * The array buffer into which the elements of the ArrayList are stored. * The capacity of the ArrayList is the length of this array buffer. Any * empty ArrayList with elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA * will be expanded to DEFAULT_CAPACITY when the first element is added. */ transient Object[] elementData; // non-private to simplify nested class access
/** * The size of the ArrayList (the number of elements it contains). * * @serial */ private int size;
/** * Constructs an empty list with the specified initial capacity. * * @param initialCapacity the initial capacity of the list * @throws IllegalArgumentException if the specified initial capacity * is negative */ public ArrayList(int initialCapacity) { if (initialCapacity > 0) { this.elementData = new Object[initialCapacity]; } else if (initialCapacity == 0) { this.elementData = EMPTY_ELEMENTDATA; } else { throw new IllegalArgumentException("Illegal Capacity: "+ initialCapacity); } }
/** * Constructs an empty list with an initial capacity of ten. */ public ArrayList() { this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA; }
/** * Constructs a list containing the elements of the specified * collection, in the order they are returned by the collection's * iterator. * * @param c the collection whose elements are to be placed into this list * @throws NullPointerException if the specified collection is null */ public ArrayList(Collection<? extends E> c) { Object[] a = c.toArray(); if ((size = a.length) != 0) { if (c.getClass() == ArrayList.class) { elementData = a; } else { elementData = Arrays.copyOf(a, size, Object[].class); } } else { // replace with empty array. elementData = EMPTY_ELEMENTDATA; } }}- An ArrayList “wraps” an array (whose default capacity is 10, but this can be changed)
ArrayList 对数组进行了“封装”(默认容量为 10,但可以调整)。 - The size field keeps track of how many elements in the array actually hold data
size 字段用于记录数组中实际存放了多少个元素。
Adding an element to an arraylist
-
Case 1: Add to end of list without exceeding capacity
情况 1:在不超过容量的前提下追加到末尾
-
Case 2: Add to end of list and exceed capacity
情况 2:追加到末尾并触发扩容
-
Case 3: Insert into list
情况 3:在中间位置插入
Performance of arraylist ArrayList
- Adding to an ArrayList can potentially mean that existing data has to be copied from one location in memory to another. This can be inefficient when the size of the list is large.
向 ArrayList 添加元素可能意味着要把已有数据从一块内存复制到另一块内存;当列表很大时,这会效率较低。 - This problem arises because an ArrayList keeps its data in a contiguous block.
这个问题产生的原因在于 ArrayList 使用连续内存块存储数据。
Linked lists
- A linked list keeps each of its elements in a separate block of memory.
链表会把每个元素存放在独立的内存块中。 - Each element has a pointer to the next element.
每个元素都包含一个指向下一个元素的指针。
Tail of list:
链表尾部:
Pointer to next element is null
指向下一个元素的指针为 null
A Class to represent nodes in linked lists (of Strings) 用于表示链表节点(字符串)的类
public class Node { String data; Node next;}Inserting data at the head of a linked list 在链表头部插入数据
public static void insertAtHead(String data) { Node newNode = new Node(); newNode.data = data; newNode.next = head; head = newNode;}Inserting data after a particular node 在指定节点后插入数据
public static void insertAfter(String data, Node insertPoint) { Node newNode = new Node(); newNode.data = data; newNode.next = insertPoint.next; insertPoint.next = newNode;}

Deleting the node at the head 删除头节点
public static void deleteHead() { head = head.next;}
Deleting the node at a particular point 删除指定位置后的节点
public static void deleteAfter(Node deletePoint) { deletePoint.next = deletePoint.next.next;}
Printing the data in a list 打印链表中的数据
public static void printList() { Node current = head; while (current != null) { System.out.println(current.data); current = current.next; }}Searching in a list 在链表中查找
// return first node in list with data value sought,// or null if not foundpublic static Node find(String sought) { Node current = head; while (current != null && !current.data.equals(sought)) { current = current.next; } // current == null || current.data.equals(sought) return current;}A simple linked List ADT (Abstract Data Type) 一个简单的链表 ADT(抽象数据类型)
- There is already a LinkedList class in the Java API, but which hides the implementation details from the user.
Java API 中已经有 LinkedList 类,但它对用户隐藏了实现细节。(更好的说法是Java标准库) Now, we try to create our own Linked list
It will help us comprehend linked list deeper
- Hide the details of the Node class by making it as a private inner class of an enclosing LinkedList class
将 Node 类设为封闭 LinkedList 类的私有内部类,从而隐藏其实现细节。
public class StringLinkedList { private static class Node { String data; Node next; } private Node head; …Brief introduction of Inner classes 内部类简介
- An inner class is defined within another class.
内部类是定义在另一个类内部的类。 - The differences between inner classes and standard classes are that:
内部类与普通类的区别在于:- Each object of the inner class is associated with an object of the enclosing class and has access to fields and methods of the enclosing object (even private ones).
每个内部类对象都关联一个外部类对象,并可访问外部对象的字段和方法(包括 private)。 - Similarly the enclosing class, has access to the fields and methods of the inner class (even private ones)
同样地,外部类也可以访问内部类的字段和方法(包括 private)。 - An inner class can be private.
内部类可以声明为 private。
- Each object of the inner class is associated with an object of the enclosing class and has access to fields and methods of the enclosing object (even private ones).
public class A { … private class B { … }}Static inner classes 静态内部类
- Normally an instance of an inner class will be associated with an instance of its enclosing class and will have access to non-static fields and methods of that class.
通常,内部类实例会绑定到某个外部类实例,并可访问该外部类的非静态字段和方法。 - If the inner class is declared to be static then it is not associated with any particular instance of the enclosing class and therefore only has access to static members of the enclosing class (because those members have the same value for all instances of the class).
如果内部类被声明为 static,它就不再绑定任何具体外部类实例,因此只能访问外部类的静态成员(因为这些成员对所有实例相同)。
public class A { private static int i; private int j; private static class B{ … }}Methods of class B can refer to the static variable i, but not the non-static variable j.
B 类的方法可以访问静态变量 i,但不能访问非静态变量 j。
UML Notation for Inner classes 内部类的 UML 表示法
public class Out { … private class In { … }}
Insertion into the linked list 向链表插入
- We previously described two methods:
前面我们介绍过两种方法:- public static void insertAtHead(String data)
- public static void insertAfter(String data, Node insertPoint)
- The first of these can be made a public method of our linked list class.
第一种可以作为链表类的 public 方法。 - The second would have to be private, because it refers to the Node class, which is now private. What we can do is define a public method like this
第二种因为涉及 Node 类(现已私有)只能设为 private;我们可以改为定义如下 public 方法。
public void insert(int index, String data) { if (index == 0) { insertAtHead(data); } else { Node insertPoint = head; for (int i = 0; i < index - 1; i++) { insertPoint = insertPoint.next; } insertAfter(data, insertPoint); }}Deletion from the list 从链表删除
- Deletion can be handled in a similar manner to insertion.
删除操作可以用与插入类似的方式处理。 - Note that both the insert and delete methods may throw a null pointer exception if the index parameter is out of range.
注意:如果 index 参数越界,insert 和 delete 方法都可能抛出空指针异常。
public void delete(int index) { if (index == 0) { deleteHead(); } else { Node deletePoint = head; for (int i = 0; i < index - 1; i++) { deletePoint = deletePoint.next; } deleteAfter(deletePoint); }}Iterating through the list 遍历链表
- There are circumstances in which we may need to iterate through all the elements in a list. For example, we might want to print them all or sum them (if they are numeric).
在某些场景下,我们需要遍历链表中的所有元素。例如打印全部元素,或在元素为数值时求和。 - We could write separate methods for all these cases, printList, addList, and so on. However, this would be cumbersome, and we can’t anticipate all cases where we might need to perform an iteration.
我们可以为这些场景分别写 printList、addList 等方法,但这种做法很繁琐,而且无法预先覆盖所有遍历需求。 - A much more elegant solution is to allow our list to create an Iterator.
更优雅的方案是让链表能够创建一个 Iterator(迭代器)。
Iterators 迭代器
- An iterator is an object that is associated with a list, and which implements (at least) the following two methods:
迭代器是与列表关联的对象,至少应实现以下两个方法: - next(): After the iterator has been created, the first call to next() returns the first element in the list, the second call returns the second element, and so on.
next():创建迭代器后,第一次调用返回第一个元素,第二次调用返回第二个元素,依此类推。 - hasNext(): a boolean method that returns true if there is another element that can be retrieved by next() and false if there is not (because we have already retrieved the last element.
hasNext():布尔方法;若后续还有可由 next() 获取的元素则返回 true,否则返回 false(表示已到最后一个元素)。 - Iterators may, optionally, implement a method remove, which deletes the next element in the list.
迭代器还可以选择性实现 remove 方法,用于删除列表中的下一个元素。
- The Java API includes an interface Iterator, that defines the three methods mentioned above.
Java API 提供了 Iterator 接口,其中定义了上面提到的三个方法。 - It also includes an interface Iterable which defines just one method iterator() which returns an iterator.
它还提供了 Iterable 接口,仅定义一个方法 iterator(),用于返回迭代器。 - Lists should implement this interface.
列表类型应实现这个接口。
public class StringLinkedList implements Iterable<String> { @Override public Iterator<String> iterator() { return new StrItr(head); } private class StrItr implements Iterator<String> {Iterator class 迭代器类
private class StrItr implements Iterator<String> { private Node current; private StrItr(Node start) {current=start;} @Override public boolean hasNext() {return (current != null);} @Override public String next() { // Thinking Question: Think more about these three statements String result = current.data; current = current.next; return result; } @Override public void remove() { throw new UnsupportedOperationException("Not supported"); }}Iterating through the list 遍历链表
- If myList implements iterable and we want to iterate through it, for example, to print out all the elements it contains, we can write:
如果 myList 实现了 iterable,并且我们希望遍历它(例如打印其中所有元素),可以这样写:
Iterator<String> iter = myList.iterator(); while (iter.hasNext()) { System.out.println(iter.next()); }- or
for (String s : myList) { System.out.println(s);}支持与分享
如果这篇文章对你有帮助,欢迎分享给更多人或赞助支持!