Chapter I overview
Section I overview of data structure
Data structure is a programming discipline that studies non numerical calculation. Nicklaus Wirth, the father of Pascal who won the Turing Award, put forward a famous formula:
Algorithm + data structure = Program
Data structure is a way for computers to store and organize data. A data structure is a collection of data elements that have one or more specific relationships with each other. In general, carefully selected data structures can bring higher operation or storage efficiency. Data structure is often related to efficient retrieval algorithm and index technology.
1. Basic concepts
(1) Data
Data is the general name of the objects processed by computer programs. For example, when calculating differential equations, the processing object is some data, and in image processing, the object is encoded image information, etc.
(2) Data Element
The basic unit of data, which can be divided into several data items, and the data item is the smallest unit of data. For example, in a student performance management system, the performance of each student can be regarded as a data element, and the performance of each subject can be regarded as different data items.
(3) Data Object
It is a collection of data elements with the same properties and a subset of data. For example, the data object of real number is real number set R.
(4) Data Structure
Is a collection of data elements that have one or more specific relationships with each other.
2. Logical structure and physical structure
(1) Logical structure
Logical structure refers to the logical relationship between data elements in data objects, which is divided into the following four structures:
- Set structure: the data elements in the set structure have no relationship except that they belong to the same set
- Linear structure: the relationship between data elements in a linear structure is a one-to-one linear relationship
- Tree structure: the elements in the tree structure have a one to many hierarchical relationship
- Graphic structure: the elements in the graphic structure have any many to many relationship
(2) Physical structure
Physical structure refers to the storage form of data logical structure in the computer, which generally has the following two forms:
-
Sequential storage structure: sequential storage structure is to store data elements in storage units with continuous addresses, and the logical relationship of data is consistent with the physical relationship. As shown below:
-
Chain storage structure: chain storage structure stores data elements in any data unit. This group of storage units can be continuous or discontinuous. As shown below:
Section II algorithm overview
The algorithm is a description of the steps to solve a specific problem, which is expressed as a finite sequence of instructions in the calculation set, and each instruction represents one or more operations.
1. Characteristics of the algorithm
The algorithm has five basic characteristics: input, output, finiteness, certainty and feasibility
- Input: the algorithm should have zero or more inputs
- Output: the algorithm has at least one or more outputs
- Finiteness: finiteness means that the algorithm ends automatically after executing limited steps without infinite loops, and each step can be completed in an acceptable time.
- Certainty: every step of the algorithm has definite significance
- Feasibility: every step of the algorithm must be feasible, and each step can be completed by executing a limited number of times
2. Requirements for algorithm design
The algorithm design has the following requirements:
- Correctness: the correctness of the algorithm means that the algorithm should at least have no ambiguity in input, output and processing, can correctly respond to the needs of the problem, and can get the correct answer to the problem
- Readability: another purpose of algorithm design is to facilitate reading, understanding and communication
- Robustness: when the input data is illegal, the algorithm can also make relevant processing, rather than producing abnormal or inexplicable results
- High time efficiency and low storage: the design algorithm should try to meet the requirements of high time efficiency and low storage
3. Measurement method of algorithm efficiency
(1) Post statistical method
This method mainly compares the running time of programs compiled by different algorithms by using computer timers through designed test programs and data, so as to determine the efficiency of the algorithm
Defects:
- It must be realized that the program is well prepared
- The comparison of time depends on environmental factors such as computer hardware and software
- The test data design of the algorithm is difficult, and the running time of the algorithm is often closely related to the scale of the test data
(2) Ex ante analysis and estimation method
Prior analysis and estimation method before computer programming, a statistical method is used to estimate the algorithm
Depends on the following factors:
- The algorithm adopts strategies and methods
- Code quality generated by compilation
- Problem input scale
- The speed at which the machine executes commands
4. Algorithm time complexity
When analyzing the algorithm, the total execution times T(n) of the statement is a function of the problem scale n, and then analyze the change of T(n) with n to determine the order of magnitude of T(n). The time complexity of the algorithm, that is, the time measurement of the algorithm, is recorded as: T(n) = O(f(n))
Common time complexity:
O ( 1 ) < O ( l o g n ) < O ( n l o g n ) < O ( n 2 ) < O ( n 3 ) < O ( 2 n ) < O ( n ! ) < O ( n n ) {O(1) < O(log n) < O(nlog n) < O(n^2) < O(n^3) < O(2^n) < O(n!) < O(n^n)} O(1)<O(logn)<O(nlogn)<O(n2)<O(n3)<O(2n)<O(n!)<O(nn)
Chapter 2 linear table (List)
Linear table (List): a linear table represents a finite sequence of zero or more data elements
Section 1 sequential storage of linear tables (ArrayList)
1. General
Definition of sequential storage: the sequential storage structure of linear table refers to storing the data elements of linear table at one time with a section of storage unit with continuous addresses, which is equivalent to one-dimensional array
Linear tables stored in sequential storage are also called ArrayList
Properties of sequence table:
- data []: an array that implements the sequence table
- size: the number of data stored in the sequence table
Method of sequence table:
·
2. Implement List and ArrayList through Java code
(1) Create List interface
package p1.interfaces; import java.util.Comparator; public interface List<E> extends Iterable<E> { public void add(E element);//Add element at end of table public void add(int index,E element);//Adds an element at the specified subscript public void remove(E element);//Deletes the specified element public E remove(int index);//Deletes the element at the specified subscript public E get(int index);//Gets the element at the specified subscript public E set(int index,E element);//Modify the element at the specified subscript public int size();//Get the number of elements public int indexOf(E element);//View the subscript position of the first occurrence of the element (from left to right) public boolean contains(E element);//See if the linear table contains elements public boolean isEmpty();//Judge whether the linear table is empty public void clear();//Empty linear table public void sort(Comparator<E> c);//The linear table is sorted according to the contents of the comparator public List<E> subList(int fromIndex, int toIndex);//In the original linear table, the sub list is intercepted by [fromIndex,toIndex) interval }
(2) Create an ArrayList class to implement the List interface
package p2.array.lists; import p1.interfaces.List; import java.util.Arrays; import java.util.Comparator; import java.util.Iterator; import java.util.Objects; public class ArrayList<E> implements List<E> { private E[] data; private int size = 0; //Default capacity private static int DEFAULT_CAPACITY = 10; //The default constructor creates a linear table of default capacity public ArrayList(){ data = (E[]) new Object[DEFAULT_CAPACITY]; size = 0; } //Creates a linear table of the specified size public ArrayList(int capacity) { if (capacity < 0){ throw new IllegalArgumentException("capacity are not be null"); } DEFAULT_CAPACITY = capacity; data = (E[]) new Object[DEFAULT_CAPACITY]; size = 0; } //Convert an array to a linear table public ArrayList(E[] array) { if (array == null || array.length == 0){ throw new IllegalArgumentException("capacity are not be null"); } data = (E[]) new Object[DEFAULT_CAPACITY]; for (int i = 0; i < array.length ; i++) { add(array[i]); } } @Override public void add(E element) { add(size,element); } @Override public void add(int index, E element) { if (index < 0 || index > size) { throw new IllegalArgumentException("add index out of range"); } if (size == data.length) { resize(2 * data.length); } for (int i = size -1; i >= index ; i--) { data[i + 1] = data[i]; } data[index] = element; size ++; } //Expansion or contraction, not provided to the outside world private void resize(int newlen) { E[] newData = (E[]) new Object[newlen]; for (int i = 0; i < size; i++) {//No subscript out of bounds newData[i] = data[i]; } data = newData; } @Override public void remove(E element) { int index = indexOf(element); if (index == -1) { throw new IllegalArgumentException("The element to be deleted does not exist"); } remove(index); } @Override public E remove(int index) { if (index < 0 || index >= size) { throw new IllegalArgumentException("remove index out of range"); } E ret = data[index]; for (int i = index + 1; i < size ; i++) { data[i - 1] = data[i]; } data[size-1] = null; size --; //When the effective element is one fourth of the capacity and the capacity is less than or equal to the default capacity, shrink the capacity if (size == data.length/4 && data.length > DEFAULT_CAPACITY) { resize(data.length/2); } return ret; } @Override public E get(int index) { if (index < 0 ||index >= size){ throw new IllegalArgumentException("get index out of range"); } return data[index]; } @Override public E set(int index, E element) { if (index < 0 ||index >= size){ throw new IllegalArgumentException("set index out of range"); } E ret = element; //data[index] = element; return ret; } @Override public int size() { return size; } private int capacity(){ return data.length; } @Override public int indexOf(E element) { /* * == Reference data type comparison address * == Basic data type comparison value * */ for (int i = 0; i < size; i++) { if (data[i] == element) { return i; } } return -1; } @Override public boolean contains(E element) { int count = indexOf(element); boolean flag = false; if (count != -1) { flag = true; } return flag; } @Override public boolean isEmpty() { return size == 0; } @Override public void clear() { data = (E[]) new Object[DEFAULT_CAPACITY]; size = 0; } @Override public void sort(Comparator<E> c){ if (c == null) { throw new IllegalArgumentException("comparator can not be null"); } for (int i = 1; i < size; i++) { E e = data[i]; int j = 0; for (j = i; j > 0 && c.compare(data[j - 1], e) > 0; j--) { data[j] = data[j - 1]; } data[j] = e; } } @Override public List<E> subList(int fromIndex, int toIndex) { if (fromIndex < 0 ||toIndex >= size || fromIndex > toIndex){ throw new IllegalArgumentException("index out of range"); } ArrayList<E> list = new ArrayList<>(); for (int i = fromIndex; i < toIndex; i++) { list.add(data[i]); } return list; } @Override public boolean equals(Object o) { //1. Empty judgment first if (o == null) { return false; } if (this == null) { return false; } if (o instanceof ArrayList) { ArrayList<E> other = (ArrayList<E>) o; if (this.size != other.size) { return false; } for (int i = 0; i < size; i++) { if (!(data[i].equals(other.data[i]))) { return false; } } return true; } return false; } @Override public String toString() { StringBuilder stringBuilder = new StringBuilder(); stringBuilder.append('['); if(isEmpty()){ stringBuilder.append(']'); }else{ for (int i = 0; i < size; i++) { stringBuilder.append(data[i]); if (i == size-1){ stringBuilder.append(']'); }else{ stringBuilder.append(','); stringBuilder.append(' '); } } } return stringBuilder.toString(); } @Override public Iterator<E> iterator() { return new ArrayListIterator(); } class ArrayListIterator implements Iterator<E>{ private int cur = 0; @Override public boolean hasNext() { return cur < size; } @Override public E next() { return data[cur++]; } } }
Section 2 stack
1. Definition of stack
Stack is a special linear table. It is limited to insert and delete operations only in one section of the linear table. One end that allows insertion and deletion is called the top of the stack and the other end is called the bottom of the stack. Because only one end is inserted or deleted, the later inserted elements will be deleted before the first inserted elements, so the stack is also called "last in first out" linear table
Stack entry (stack entry, stack pressing): the process of adding elements to the stack
Out of stack (pop stack): delete the elements in the stack
2. Realize Stack and ArrayStack through code
(1) Define Stack interface
package p1.interfaces; public interface Stack<E> extends Iterable<E> { public int size();//Returns the number of elements currently stored in the stack public boolean isEmpty();//Determine whether the stack is empty public void push(E element);//Stacking (pressing) operation public E pop();//Out of stack (pop stack) operation public E peek();//Get stack top element public void clear();//Empty stack }
(2) Implement the Stack interface through the ArrayStack class
package p2.array.lists; import p1.interfaces.Stack; import java.util.Iterator; public class ArrayStack<E> implements Stack<E> { ArrayList<E> list ; public ArrayStack(){ list = new ArrayList<>(); } public ArrayStack(int capacity){ list = new ArrayList<>(capacity); } public ArrayStack(E[] arr){ list = new ArrayList<>(arr); } @Override public int size() { return list.size(); } @Override public boolean isEmpty() { return list.isEmpty(); } @Override public E pop() { return list.remove(list.size()-1); } @Override public E peek() { return list.get(list.size() - 1); } @Override public void clear() { list.clear(); } @Override public void push(E element) { list.add(list.size(), element); } @Override public String toString() { return list.toString(); } @Override public Iterator iterator() { return list.iterator(); } }
3. Stack application: infix expression operation
(1) Definition of infix expression
- It is a general expression method of arithmetic or logic formula. The operator is in the middle of the operand in the form of infix (example: 3 + 4)
- Compared with prefix expression (e.g. + 34) or suffix expression (e.g. 34 +), infix expression is not easy to be parsed by computer, but it is still used by many programming languages because it conforms to people's common usage.
- Unlike prefix or suffix notation, infix notation brackets are required.
(2) Overview of infix expression operation implementation process
with ( 10 + 20 / 2 ∗ 3 ) / 2 + 8 {(10+20/2*3)/2+8} (10 + 20 / 2 * 3) / 2 + 8 as an example
First, you can add an appropriate delimiter to the infix expression to split the expression and initialize the string
public static String initString(String expression){ //Add spaces at both ends of all non numeric characters //Traverse the string from left to right and use stringbuilder to splice StringBuilder stringBuilder = new StringBuilder(); char c; for (int i = 0; i < expression.length(); i++) { c = expression.charAt(i); if (c=='('||c==')'||c=='+'||c=='-'||c=='*'||c=='/'){ stringBuilder.append(','); stringBuilder.append(c); stringBuilder.append(','); }else{ stringBuilder.append(c); } } return stringBuilder.toString(); }
Secondly, divide the string, define two stacks, one for storing operators and the other for storing numbers, and then operate on these stacks.
private static int eValuete(String expression) { ArrayStack<Character> operator = new ArrayStack<>(); ArrayStack<Integer> integers = new ArrayStack<>(); //1. Initialize the expression and add spaces on both sides of each symbol expression = initString(expression); //2. Cut the string xz String[] tokens = expression.split(","); for (String token:tokens) { //Filter empty strings if (token.length() == 0){ continue; }else if (token.equals("+") || token.equals("-")){//When traversing to the plus and minus sign, look at the top of the stack. There are no elements at the top of the stack. Go directly in while(!operator.isEmpty() && (operator.peek() == '+' || operator.peek() == '-' || operator.peek() == '*' || operator.peek() == '/')){ //If the previous operator is + - * / or other operators, pop stack calculation processAnOperator(integers,operator); } operator.push(token.charAt(0)); }else if (token.equals("*") || token.equals("/")){ while(!operator.isEmpty() && (operator.peek() == '*' || operator.peek() == '/')){ //If the previous operator is + - * / or other operators, pop stack calculation processAnOperator(integers,operator); } operator.push(token.charAt(0)); }else if(token.equals("(")){ operator.push(token.charAt(0)); }else if(token.equals(")")){ while(operator.peek() != '('){ //If the previous operator is + - * / or other operators, pop stack calculation processAnOperator(integers,operator); } operator.pop(); }else{ integers.push(Integer.parseInt(token)); } } //Process the last operator while(!operator.isEmpty()){ processAnOperator(integers,operator); } return integers.pop(); } //The operator stack bounces one element, the number stack bounces two elements and operates, and then the result is put on the stack private static void processAnOperator(ArrayStack<Integer> integers, ArrayStack<Character> operator) { char op = operator.pop(); int num1 = integers.pop(); int num2 = integers.pop(); if (op == '+') { integers.push(num2 + num1); } else if (op == '-') { integers.push(num2 - num1); } else if (op == '*') { integers.push(num2 * num1); } else { integers.push(num2 / num1); } }
Finally, we are testing these functions with a main()
public static void main(String[] args) { String expression = "(10+20/2*3)/2+8"; try { int result = eValuete(expression); System.out.println(result); } catch (Exception e) { e.printStackTrace(); System.out.println("Wrong expression :" + expression); } }