To save content items to your account,
please confirm that you agree to abide by our usage policies.
If this is the first time you use this feature, you will be asked to authorise Cambridge Core to connect with your account.
Find out more about saving content to .
To save content items to your Kindle, first ensure no-reply@cambridge.org
is added to your Approved Personal Document E-mail List under your Personal Document Settings
on the Manage Your Content and Devices page of your Amazon account. Then enter the ‘name’ part
of your Kindle email address below.
Find out more about saving to your Kindle.
Note you can select to save to either the @free.kindle.com or @kindle.com variations.
‘@free.kindle.com’ emails are free but can only be saved to your device when it is connected to wi-fi.
‘@kindle.com’ emails can be delivered even when you are not connected to wi-fi, but note that service fees apply.
Package and interface are two incredible concepts in Java programming language. These features make Java programming suitable for developing large software in any application domain. The concept of package and interface allows the programmers to organize classes and hence methods and fields or constants for developing a large software program. This concept is called programming in large. It also helps the programmers to write code in their own styles, which is called programming in small. With this you will feel Java is like C when programming in small and like Smalltalk (a pure object-oriented programming language) when programming in large. This means that Java is powerful like any function-oriented programming language while you are coding individual lines, and has the extensibility and expressive power of a pure object-oriented programming language while you’re designing.
Introduction
From design to coding The separation of “designing” from “coding” was one of the most fundamental advances in programming style in the recent past, and object-oriented languages are capable of implementing a strong form of this separation. According to this programming paradigm, you design the classes first and decide the relationships between these classes, and then you implement the Java code needed for each of the methods in your class design. The advantages with this style is that, you can change your mind about aspects of the design without affecting anything but small, local pieces of your programs; vice-versa, you can change the implementation of any method without affecting the design.
To achieve this, the Java developer includes two very innovative features: package and interface. Packages provide class repositories, grouping them together, and controlling their access to the outside world. Interfaces provide a way of grouping abstract method definitions and sharing them among classes.
Your learning This chapter plans to discuss the package and interface concepts in Java. You will learn how to design, use, and create your own packages and interfaces. The specific topics which you will learn include: a detailed discussion of designing classes and coding classes; what are packages and why they are useful for designing classes; using other available packages in your own classes; how you can create your own packages; what interfaces you can utilize in terms of code reuse and design; designing and working with interfaces; and many more.
Another important data structure is queue. Queues are also exhaustively used in various situations in computer science. In this chapter we will discuss the operations related to queues; how a queue is represented in memory, both array and linked representation of queues, different types of queues and various applications of queues.
9.1 Definitions and Concept
A queue is a linear data structure in which insertion and deletion operations take place at two different ends. The insertion operation is commonly known as ENQUEUE and the deletion operation is known as DEQUEUE. These two operations take place at two different ends. The end at which elements are inserted is known as the rear end and the other end at which elements are deleted from the queue is known as the front end. Elements are inserted through the rear end and removed through the front end following the First-In-First-Out (FIFO) order, i.e. in the order the elements entered the queue they will leave the queue maintaining the same order. In real life we are very familiar with queues. We can see several queues in our surroundings. For example, passengers standing in front of a railway ticket booking counter. The passenger who stands at the first position gets the ticket first and when a new passenger comes, he joins the queue at the end. The same can be seen when passengers wait at a bus stop, people standing in front of a ticket counter in a cinema hall, luggage moving through conveyor belt, cars passing through single lane in a one-way road, etc.
9.2 Operations Associated with Queues
The basic operations related to a queue are as follows:
• Enqueue: Insert an element into a queue.
• Dequeue: Retrieve an element from a queue.
Apart from these basic two operations, to use a queue efficiently we need to add the following functionalities:
• Peek: Get the front element of a queue without removing it.
• Isempty: To check whether a queue is empty or not.
• Isfull: To check whether a queue is full or not.
All these operations execute with the time complexity O(1).
Like in stack, the peek operation is required to check the front element of the queue without removing it. And if a queue is full, the enqueue operation cannot be done on the queue. Similarly, dequeue and peek operations cannot be performed on an empty queue.
A simple method for adding uncertainty to neural network regression tasks in earth science via estimation of a general probability distribution is described. Specifically, we highlight the sinh-arcsinh-normal distributions as particularly well suited for neural network uncertainty estimation. The methodology supports estimation of heteroscedastic, asymmetric uncertainties by a simple modification of the network output and loss function. Method performance is demonstrated by predicting tropical cyclone intensity forecast uncertainty and by comparing two other common methods for neural network uncertainty quantification (i.e., Bayesian neural networks and Monte Carlo dropout). The simple approach described here is intuitive and applicable when no prior exists and one just wishes to parameterize the output and its uncertainty according to some previously defined family of distributions. The authors believe it will become a powerful, go-to method moving forward.
Recursion is a very important concept in programming technique. In programming there are situations where we may find that the solution of a problem can be achieved by solving smaller instances of that same problem. For example, in tree data structure, all the properties that comprise a tree also feature in its sub-trees. So, to get a solution for the tree first we need to get the solution of its sub-trees. Again to get the solution of a sub-tree we need to get the solution of the sub-trees of this sub-tree, and so on. This is the basis of recursion. This concept helps to solve many complex problems very easily.
6.1 Definition
In almost every programming language, a function or procedure may invoke other functions or procedures. Not only from other functions, a function may be invoked from within itself as well. When a function is invoked by itself, the function is called a recursive function. And the process is called recursion. Instead of direct invocation, it may happen that the first function invokes the second function and the second function again invokes the first function in turn. This is also recursion. So, we can define recursion as the process where a function is directly or indirectly invoked by itself. Though it is a comparatively more memory consuming process, it is very effective in implementation where the algorithm demands the same repetitive process but use of iteration is difficult.
For example, we can define factorial of n as n! = n * (n-1)!. So, to find the factorial of n we need to calculate factorial of n-1 first. Again, to calculate the factorial of n-1 we need to calculate factorial of n-2, and so on. But this process may not continue indefinitely. Stack will be overflowed in that case. Hence, we must impose some criteria based on which this invocation should be restricted. This is called base criteria or base condition. Thus, every recursive function must have a base condition. In the above example, we may set the base condition as: when the value of n is 0, instead of recursive call it directly returns 1.
In the previous two chapters we have studied about arrays and other in-built data structures like lists, tuples, sets and dictionaries. In this chapter we will discuss another in-built data type/data structure of Python, and that is string. In programming languages, string handling is a very important task and in data structure we will learn about different algorithms for efficient string handling.
5.1 Introduction
A string is a sequence of characters allocated contiguously in memory where the characters may be letters of the alphabet, digits, punctuation marks, white spaces or any other symbols. In Python a string is implemented as an object of the in-built class str. To define a string constant we may use single quotation (‘ ’), double quotation (“ ”) or triple quotation (‘“ ”’). So, ‘India’, “India” and ‘“India”’ – all three are valid string constants in Python. Apart from a normal string, there are two other types of strings. These are escape sequences and raw strings. Like C, C++ and Java programming, Python also supports escape sequences. An escape sequence is the combination of a backslash (\) and another character that together represent a specific meaning escaping from their original meaning when used individually. Table 5.1 shows some escape sequences in Python.
The following example shows the use of escape sequences:
Example 5.1: Example to show the use of escape sequences.
print(“Hello \nClass!!”)
Output:
Hello
Class!!
print(“Hello \tClass!!”)
Output:
Hello Class!!
print(‘Cat\rM’)
Output:
Mat
print(‘Cat\b\bu’)
Output:
Cut
print(“Welcome to the world of \‘Python\’”)
Output:
Welcome to the world of ‘Python’
print(“\”India\” is great.”)
Output:
“India” is great.
If a string is preceded by an ‘r’ or ‘R’, then it is called a raw string. Within a raw string, escape sequence do not work. They behave like a normal character. Consider the following example:
Example 5.2: Example to show the use of raw string.
print(‘Techno\nIndia’)
Output:
Techno
India
print(r‘Techno\nIndia’)
Output:
Techno\nIndia
print(‘Techno\\India’)
Output:
Techno\India
print(R‘Techno\\India’)
Output:
Techno\\India
5.2 Basic String Operations
Strings are immutable in Python. Hence, we cannot modify a string. But we can create a new string after manipulating an old string. We can extract an individual character or portion of a string. Characters within a string are accessed using the subscript operator and the index value.
In this chapter we will discuss an important data structure: a heap. Though there are several variations of this data structure, such as binary heap, d-ary heap, B heap, Fibonacci heap, etc., we will discuss here the most popular heap data structure – the binary heap. In the following sections we will mention heap to indicate the binary heap.
11.1 Definition and Concept
Heap is a very important tree-based data structure. It is widely used in computer science. We can define a heap as a binary tree that has two properties. These are: shape property and order property. By shape property, a heap must be a complete binary tree. By order property, there are two types of heaps. One is max heap and the other is min heap. By default, a heap means it is a max heap. In max heap, the root should be larger than or equal to its children. There is no order in between the children. This is true also for its sub-trees. In min heap the order is the reverse. Here the root is smaller than or equal to any of its children. Thus the root of a max heap always provides the largest element of a list whereas the root of a min heap always provides the smallest element. As a heap is a complete binary tree, its maximum height is O(log2n) where n is the total number of elements. Thus both the insertion of new node and the deletion of an existing node can be done in O(log2n) time. Figure 11.1 shows a max heap and a min heap.
11.2 Representation of a Heap in Memory
Like other data structures, a heap also can be represented in memory using an array (or a list in Python) and a linked list. The main problem in tree representation using arrays is in wastage of memory. But in case of complete binary tree representation, that chance is almost nil. Moreover, we need not waste space for storing references of left and right children. So, using arrays (or lists in Python) we can represent the heap data structure efficiently.
Java is the most suitably programming language for developing application software for a distributed environment with concurrent execution. To enable this, Java has been designed as a multithreaded programming language. This means that a program can be executed with one or more threads to solve a problem while utilizing the computing resources in the most efficient manner. Since the inception of Java, an elegant feature called “multithreading” has been introduced. With this unique feature, a programmer can write a program with multiple flows of executions along with robust control in the executions. More significantly, Java is a lightweight programming language that is designed to have a very small memory footprint, it has minimalist syntax and features, and it is easy to port an implementation to different systems.
Introduction
Why multithreading? Multitasking is a very common features in today’s computation environment. Java supports thread-based approach to multi-tasking, which is more precisely called multithreading. Multithreading means multiple flow of control. Multithreading programming is a conceptual paradigm for programming where one can divide a program into two or more processes which can be run in parallel. There are two main advantages of multithreading: First, a program with multiple threads will, in general, result in better utilization of system resources, including the CPU, because another line of execution can use the CPU when one line of execution is idle or blocked. Second, there are several problems which are solved better by multiple threads. For example, we can easily write a multithreaded program to show animation, play music, display documents, and download files from the network, etc., all of them at the same time.
Heavyweight versus lightweight programming Multitasking involves complex processing that an execution environment has to perform while it executes the program. If processes are heavyweight tasks, they require their own separate address spaces. The inter-process communication becomes expensive and reduces the advantages of the concurrent execution. Context switching from one process to another is also costly. Java follows the concept of threads and thus the concept of thread-based multitasking. All the threads are lightweights, which share the same address space. Hence interthread communication remains inexpensive and context switching from one thread to the next is at a lower cost.
Patterns of underwater human-generated noise events and durations of noise-free intervals (NFIs) are soundscape metrics that can potentially affect animal communication and behavior. Due to the arduous task of manual analysis, these metrics have not been described in Glacier Bay National Park and Preserve (GBNP). To surmount this challenge, we created a machine-learning (ML) model trained on 18 hr of labeled audio samples from a hydrophone operating in GBNP since 2000. The validated convolutional neural net transfer-learning model (GBNP-CNN) was used to classify several categories of sound sources in nearly 9,000 hours of data from the same hydrophone, enabling our study of vessel noise between 2017 and 2020. We focused on the occurrence and duration of NFI and the hourly proportion (HP) of vessel noise. As expected, shorter NFI and higher HP were found during daytime hours. The GBNP-CNN F1 score was 75%, largely due to the model’s confusion of vessel noise with harbor seal roars. Therefore, NFI lengths should be considered minimum estimates, but the errors do not qualitatively affect diurnal or seasonal patterns. In 2018, mean daytime NFI during peak tourism months (June–August) was less than half the duration compared to May and September (1.3 min vs. 2.9 min). In 2020, when large-vessel tourism was substantially reduced but small-craft activity continued, we found that HP decreased in June–August. In conjunction with other soundscape metrics, monitoring NFI trends using ML models such as GBNP-CNN will provide crucial information for management and conservation of acoustic habitats and sensitive species in GBNP.
Java developer aims at Java programming suitable for fast, large, complex, and safety-critical software development. One important requirement towards this is to code reusability. Code reusability helps a programmer to use code which is already developed by someone else. For this reason, Java developer introduces one of the most magnificent object-oriented programming features called inheritance. This feature allows a programmer to access fields and methods of an existing class to their new class under development. Inheritance thus facilitates inheriting some of the characteristics in a child class from its parent class. It is just like a ladder from the child class to the parent class. In addition to code sharing, access privilege is also taken into consideration in the inheritance mechanism. This enables protection of data and code from unauthorized access.
Introduction
Why inheritance? Class is the basic element of any software in object-oriented system design approach. In the last chapter, you have learned about how to write classes in Java programs. In software development, a software is under constant updation, for example, extension (from one version to the next or from one release to another, etc.), or modification (correction of some faults or to make it compatible with new technology, hardware, etc.). The requirement is that all the development should take place without disturbing the existing system and, of course, with minimum effort and time.
Your learning Inheritance in Java is a clever mechanism to support these requirements. It allows an efficient and secure way to share code, modify it, and reuse it. With the help of inheritance, you will learn how to extend a given class and thus access its fields and methods. You will also learn how to hide some fields and methods from a parent class to the extended class.
Concept of Inheritance
Basic concept The inheritance concept is related to taxonomy or classification. For example, Figure 4.1 shows taxonomy (in partial form) of animals. It looks like a tree (this is why it is also called and inheritance tree). This tree bears the information that lion and hyena, for example, have some common characteristics. In addition, they have their own characteristics.
In 2016, Lawley proposed an easy-to-build spellchecker specifically designed to help second language (L2) learners in their writing process by facilitating self-correction. The aim was to overcome the disadvantages to L2 learners posed by generic spellcheckers (GSC), such as that embedded in Microsoft Word. Drawbacks include autocorrection, misdiagnoses, and overlooked errors. With the aim of imparting explicit L2 spelling knowledge, this correcting tool does not merely suggest possible alternatives to the detected error but also provides explanations of any relevant spelling patterns. Following Lawley’s (2016) recommendations, the present study developed a prototype computer-based pedagogic spellchecker (PSC) to aid L2 learners in self-correcting their written production in Spanish. First, a corpus was used to identify frequent spelling errors of Spanish as a foreign language (SFL) learners. Handcrafted feedback was then designed to tackle the commonest misspellings. To subsequently evaluate this PSC’s efficacy in error detection and correction, another learner Spanish corpus was used. Sixty compositions were analysed to determine the PSC’s capacity for error recognition and feedback provision in comparison with that of a GSC. Results indicate that the PSC detected over 90% of the misspellings, significantly outperforming the GSC in error detection. Both provided adequate feedback on two out of three detected errors, but the pedagogic nature of the former has the added advantage of facilitating self-learning (Blázquez-Carretero & Woore, 2021). These findings suggest that it is feasible to develop spellcheckers that provide synchronous feedback, allowing SFL learners to confidently self-correct their writing while saving time and effort on the teacher’s part.
In the previous chapter we have discussed three different searching techniques. Linear search works on both ordered and unordered data but time complexity is O(n). Binary search works on only ordered data but time complexity is O(log2n) which is much faster than linear search. Interpolation search generally works faster than binary search and its time complexity is O(log2(log2n)) when elements are evenly distributed. But there is another application where, irrespective of the size of the array/list, a search operation can be performed with time complexity O(1), i.e. in constant time. This is possible due to hashing. In this chapter we will discuss this.
14.1 Definitions and Concept
Hashing is a procedure by which we can store or retrieve data in constant time, i.e. with time complexity O(1). To achieve O(1) time complexity we may follow a simple process. Suppose we have to store the data of students whose roll numbers range from 1 to 60. For this purpose we may take an array/list and store the data of each student at the corresponding index position which matches with the roll number. In this situation, to access a student, if we know his/her roll number, we can directly access his/her data. For example, if we want to read the data of the student whose roll number is 27, we may directly access the 27th index position of the array/list. But the problem is that in real life key values are not always as simple. You may find that in a certain university someone's roll number may be 21152122027. This does not imply that it is a sequential number, nor that this number of students are admitted in a year in that university. It may be a nomenclature of a key value where the first two digits may denote the year of registration, the next three digits are the college code, the next two digits may indicate stream, and so on. This is true for not only roll numbers but also any other key value. Thus it is clear that the number of digits does not indicate the total number of elements. In the above example hardly 10,000 or 20,000 students may take admission in that university in a year.
Algorithm is a very common word in computer science, especially in case of any procedural programming languages. In this chapter we will know about algorithms, different types of algorithms, different approaches to designing an algorithm, analysis of algorithms, etc. We will also be able to learn how an algorithm can be written using different control structures.
2.1 What Is an Algorithm?
We can define an algorithm as a step-by-step procedure to solve a problem. This is much like a recipe for cooking an item. To cook a new item, we follow the instructions one by one as given in its recipe. Similarly, to write a program we need to follow the algorithm. Once we are able to generate the algorithm of a problem, then writing its code is not a huge task at all. But before writing an algorithm we have to keep in mind that any algorithm must have the following characteristics:
• Input: Inputs are the values that are supplied externally. Inputs are those without which we cannot proceed with the problems. Every algorithm must have zero or any number of inputs.
• Output: Output is the outcome of an algorithm. Every algorithm produces at least one output.
• Definiteness: All the instructions in the algorithm must be clear and should not be ambiguous.
• Finiteness: Whatever may be the inputs for all possible values, every algorithm must terminate after executing a finite number of steps.
• Effectiveness: All the instructions in the algorithm should be very basic so that every instruction of the algorithm can be converted to programming instruction easily. Effectiveness indicates that every instruction is a step towards the solution.
• Feasible: Every instruction must be a feasible instruction.
2.2 Importance of an Algorithm
When we try to write a program, first we need to identify all the tasks. Some tasks are easily identifiable while some tasks maybe hidden within the problem definition. For that a detailed analysis of the problem is required. After proper analysis we are able to find what the expected output is. What are the inputs required using which we can get the output? Using the inputs how we reach the solution? To accomplish this ‘how’, after identifying all the tasks we need to arrange them in a proper sequence.
Input and output are two most important operations in any software system design. This is particularly significant with modern Internet and communication technology where there are many modes of input–output from many sources. This versatility of input–output brings a challenge to software systems developer. Fortunately, Java developer has java.io, which provides a brilliant method of managing data in an easy, programmer-friendly, reliable, and robust manner. Today java.io API is admired as one of the finest packages which facilitates data manipulation in the best possible way. The addendum java. nio offers several features to implement intensive and high-speed IO operations. This chapter gives you an understanding of handling input-output in programs in Java.
Introduction
Real-world programming requirements In the previous chapters, you have studied a little about input and output related methods in Java. Chapter 2 mentioned input to programs and output from programs considering the programs are simple and text-based (reading from keyboard), and writing output on the console (display). However, in many real world applications, input–output are more versatile: inputs are from many different sources (such as files, other programs, network channels, etc.); similarly, outputs from a program may go into several destinations like files, external programs, network lines in web, etc. (Figure 8.1).
Java’s key to success While a majority of programming languages are keyboard–console input and output (IO), Java is much ahead of them, supporting efficient, strong, and flexible real-world programming with networking, files, and many more options. Java includes the java.io package which contains nearly every class you might ever need to perform IO. As a unique concept, Java introduced stream for flow of different forms of data to-and-fro the sources and destinations. There are numerous classes representing different streams for input sources and output destinations. The streams in the java.io package support many kinds of data such as primitives, object, localized characters, etc.
The java.io package is vast. It defines over seventy classes and interfaces, many of which have a large number of methods. Covering all of them in detail is beyond the scope of this book and often it is not necessary for a programmer to know about them.
So far we have discussed different linear data structures like arrays, linked lists, stacks, queues, etc. These are called linear data structures because elements are arranged in linear fashion, i.e. one after another. Apart from these there are also some non-linear data structures. Trees and graphs are the most common non-linear data structures. In this chapter we will discuss the tree data structure. A tree structure is mainly used to store data items that have a hierarchical relationship among them. In this chapter we will discuss the different types of trees, their representation in memory, and recursive and non-recursive implementation.
10.1 Definition and Concept
A tree is a non-linear data structure that is used to represent hierarchical relationship among data items. Basically a tree is an acyclic and connected graph. It consists of some nodes and these nodes are connected by edges. The topmost node or starting node is known as root. Zero or more nodes can be connected with this root node through edges. The structure of a tree is recursive by its nature. Each node connected with the root node may be further considered as a root node with which some other nodes can be connected to form a sub-tree. Thus, a tree, T, can be defined as a finite non-empty set of elements among whose one is root and others are partitioned into trees known as sub-trees of T. Figure 10.1 shows a sample tree structure.
10.2 Terminology
In this section we will know about the basic terminologies of trees considering Figure 10.1.
Node: It is the main component of a tree. It contains the data elements and the links to other nodes. In the above tree, A, B, C, D, etc. are the nodes.
Root Node: The topmost node or starting node is known as the root node. Here A is the root node.
Edge: It is the connecter of two nodes. In Figure 10.1, the line between any two nodes can be considered as an edge. As every two nodes are connected by a single edge only, there should be exactly n-1 edges in a tree having n nodes.