data structure
summary
Data structure (English: data structure) is a way of storing and organizing data in a computer.
Data structure is a set of data elements with certain logical relationship, which applies a certain storage structure in the computer and encapsulates the corresponding operations. It includes three aspects: logical relationship, storage relationship and operation.
Different kinds of data structures are suitable for different kinds of applications, and some are even dedicated to specific tasks. For example, computer networks rely on routing tables to operate, and B-trees are highly suitable for database encapsulation.
- Data:
- Data is the general name of numerical values, characters describing objective things and various symbol sets that can be input into the machine and processed.
- Data item:
- The smallest and indivisible identification unit with independent meaning in a data element.
- For example, the name, gender and student number describing the relevant information of students are data items
- Data element:
- A set of data representing a thing.
- For example, a data record describing the complete information of a student is a data element;
- Data object:
- A data object is a collection of data elements with the same properties and a subset of data.
- For example, the collection of all students in a school is a data object, and the combination of all points in space is also a data object.
- keyword:
- In a data element, one or more data items that can identify the element
- Primary key:
- Keywords that uniquely identify data elements
- Node:
- The storage unit storing a data element is called a node, and a node at least includes: data field storing data elements; An address field (also known as a chain) stores the address of a predecessor or successor element
Common data structures
- Stack: stack is a special line representation. It can only insert and delete data nodes at one fixed end of a table.
- Queue: similar to stack, queue is also a special line representation. Different from the stack, the queue only allows insertion at one end of the table and deletion at the other end.
- Array: an array is an aggregate data type. It is a collection that orderly organizes several variables of the same type.
- Linked List: a Linked List is a data structure in which data elements are stored in a chain structure. This storage structure has the characteristics of physical discontinuity.
- Tree: a tree is a typical nonlinear structure. It is a finite set K including two nodes.
- Graph: graph is another nonlinear data structure. In graph structure, data nodes are generally called vertices, and edges are ordered pairs of vertices.
- Heap: heap is a special tree data structure. Generally, the heap discussed is binary heap.
- Hash Table: the Hash Table is derived from the Hash function. Its idea is that if there is a record with the same keyword and T in the structure, the record must be found in the storage location of F(T), so that the queried record can be obtained directly without operation.
Data structure classification
Storage structure of data:
The storage structure of data mainly includes the storage of data elements themselves and the representation of the relationship between data elements. It is the representation of the logical structure of data in the computer.
storage structure
Sequential storage structure:
Logically adjacent nodes are stored in physically adjacent storage units, and the logical relationship between nodes is reflected by the adjacency relationship of storage units.
- Advantages: it saves storage space, because the storage units allocated to the data use all the data of the nodes, and the logical relationship between the nodes does not occupy additional storage space.
- Disadvantages: insertion and deletion operations need to move elements, which is inefficient
Chained storage structure:
The storage of data elements corresponds to discontinuous storage space, and each storage node corresponds to a data element to be stored.
Each node consists of roommate data field and pointer field. The logical relationship between elements is reflected by the link relationship between storage nodes.
- characteristic:
- The storage density is lower than that of sequential storage structure
- Logically adjacent nodes are physically no better than adjacent nodes
- Flexible insertion and deletion (no need to move the node, just change the pointer in the node)
- Chained storage is slower than sequential storage when finding nodes
Index storage structure: in addition to establishing storage node information, additional index representation is also established to identify the address of the node. For example, the catalogue of books and dictionaries.
Hash storage structure: directly calculate the storage address of the node according to the keyword of the node
Logical structure
array
Basic use of arrays
public class TestArray { public static void main(String[] args) { //Create a data int[] arr1 = new int[3]; //Get array length int length1 = arr1.length; System.out.println("arr1's length: " + length1); //Access the elements in the array: array name [subscript] Note: the subscript starts from 0, and the maximum length can be - 1 int element0 = arr1[0]; System.out.println("element0:" + element0); // Assign values to elements in the array arr1[0] = 99; System.out.println("element0:" + arr1[0]); arr1[1] = 99; arr1[2] = 97; // Traversal array for (int i = 0; i < length1; i++) { System.out.println("arr1 element" + i + ":" + arr1[i]); } //Assign values to the elements in the array while creating the array int[] arr2 = new int[] {90,80,70,60,50}; //Gets the length of the array System.out.println("arr2 length:"+ arr2.length); } }
Addition of array elements
public class TestOpArray { public static void main(String[] args) { // Solve the problem that the length of the array is not variable int[] arr = new int[]{9,8,7}; //Quick view of elements in an array System.out.println(Arrays.toString(arr)); //The target element to be added to the array int dst = 6; //Create a new array with the length of the original array + 1 int[] newArr = new int[arr.length+1]; //Copy all the data in the array to the new array for (int i = 0; i < arr.length; i++) { newArr[i] = arr[i]; } //Put the target element at the end of the new array newArr[arr.length] = dst; //Replace the original array with the new array arr = newArr; System.out.println(Arrays.toString(arr)); } }
Deletion of array elements
public class TestOpArray2 { public static void main(String[] args) { int[] arr = new int[] {9,8,7,6,5,4}; int dst = 0; System.out.println(Arrays.toString(arr)); int[] newArr = new int[arr.length - 1]; for (int i = 0; i < newArr.length; i++) { if (i<dst) { newArr[i] = arr[i]; }else { newArr[i] = arr[i+1]; } } arr = newArr; System.out.println(Arrays.toString(arr)); } }
Object oriented array
public class Myarray { private int[] elements; public Myarray() { elements = new int[0]; } //Method to get array length public int size() { return elements.length; } //Add an element to the end of the array public void add(int element) { //Create a new array int[] newArr = new int[elements.length + 1]; //Copy the elements from the original array to the new array for (int i = 0; i < elements.length; i++) { newArr[i] = elements[i]; } //Put the added elements into the new array newArr[elements.length] = element; //Replace old array with new array elements = newArr; } //Print all elements to the console public void show() { System.out.println(Arrays.toString(elements)); } //Delete elements in array public void delete(int index) { //Judge whether the subscript is out of bounds if (index<0 || index>elements.length-1) { throw new RuntimeException("Subscript out of bounds"); } //Create a new array with the length of - 1 of the original array int[] newArr = new int[elements.length-1]; for (int i = 0; i < newArr.length; i++) { //The element before the element you want to delete if (i<index) { newArr[i] = elements[i]; }else { newArr[i] = elements[i+1]; } } elements = newArr; } //Get an element public int get(int index) { return elements[index]; } //Inserts an element into the specified location public void insert(int index, int element) { //Judge whether the subscript is out of bounds if (index<0 || index>elements.length-1) { throw new RuntimeException("Subscript out of bounds"); } //Create a new array int[] newArr = new int[elements.length+1]; //Put the elements of the original array into the new array for (int i = 0; i < elements.length; i++) { //Element before target location if (i<index) { newArr[i] = elements[i]; //Position after target element }else { newArr[i+1] = elements[i]; } } //Insert new element newArr[index] = element; //Replace old array with new array elements = newArr; } //Replace the element at the specified location public void set(int index, int element) { //Judge whether the subscript is out of bounds if (index<0 || index>elements.length-1) { throw new RuntimeException("Subscript out of bounds"); } elements[index] = element; } //binary search public int binarySearch(int target) { //Record start position int begin = 0; //Record end position int end = elements.length-1; //Record the middle position int mid = (begin+end)/2; //Record target location int index=-1; //Circular search while(true) { //When is there no such element? //If the start is after or coincident with the end position if (begin>=end) { return -1; } //Judge whether the element in the middle is the element to be found if(elements[mid]==target) { return mid; //The middle element is not the element to be checked }else { //Judge whether the middle element is larger than the target element if(elements[mid]>target) { //Adjust the end position to the position before the middle position end=mid-1; //The middle element is smaller than the target element }else { //Adjust the start position to the next position in the middle position begin = mid+1; } //Take out the new middle position mid=(begin+end)/2; } } } }
Linear table
A linear table is a finite sequence of n data elements of the same type, which is usually recorded as (a0, a1, a2..., an-1)
- Same data type
- You can see that n data elements from a0 to an-1 are elements with the same attributes
- The same data type means that when stored in memory, each element will occupy the same memory space for subsequent query positioning
- Sequence (sequential)
- There is an order pair relationship between adjacent data elements of a linear table
- That is, ai-1 is the direct precursor of ai, and a i is the direct follow-up of a i-1
- Except for the header and footer elements, any element has a cut, with only one direct precursor and direct successor.
- Limited
- The number of data elements n in the linear table is defined as the length of the linear table, that is, n is a finite value.
Storage structure of linear table
- Sequential table - sequential storage structure
- Array: stores a collection of elements with the same data type.
- Sequential table: the sequential storage structure of linear table is called sequential table.
- advantage:
- The storage space is saved because the storage units allocated to the data all use the data of the nodes, and the logical relationship between the nodes does not occupy additional storage space.
- The index search efficiency is high, that is, each node corresponds to a serial number, from which the storage address of the node can be calculated directly.
- Disadvantages:
- Insert and delete operations need to move elements, which is inefficient.
- A fixed amount of space must be allocated in advance. If there are few storage elements, it may lead to idle waste.
- Query by content is inefficient because it needs to be compared and judged one by one
- Linear linked list -- linked storage structure
- The storage of data elements corresponds to discontinuous storage space, and each storage node corresponds to a data element to be stored.
- A linear linked list with only one address field per node is called a single linked list
- The first and last nodes of the linked list are called the first and last nodes of the linked list respectively
- An important feature of a single linked list is that it can only find subsequent nodes through the precursor nodes, but can not find the precursor nodes from the subsequent nodes.
- The search operation in the single linked list can only start from the first node of the linked list, and each node in the linked list can be accessed once through the next reference of each node to complete the corresponding search operation
- The storage space of nodes in the single linked list is dynamically applied for and released in the process of insertion and deletion. It is not necessary to allocate storage space to the single linked list in advance, so as to avoid the process of expanding space and copying elements due to insufficient storage space in the sequential table, and improve the operation efficiency and utilization of storage space.
- In order to make the program more concise, a dummy node, also known as the head node, is usually added at the front of the single linked list.
- No real data objects are stored in the header node, and its next field points to the node where element 0 in the linear table is located. The situation of empty table, non empty table and the first element node can be processed uniformly, which is more convenient for programming
- The head pointer of the empty single linked list is null, and the address field of the last node of a single linked list is null, indicating that there are no more nodes thereafter.
Single linked list
Implementation of single linked list
//One node public class Node { //Node content int data; //Next node Node next; public Node(int data) { this.data=data; } //Append node to node public Node append(Node node) { //Current node Node currentNode = this; //Loop back while(true) { //Take out the next node Node nextNode = currentNode.next; //If the next node is null, the current node is already the last node if(nextNode==null) { break; } //Assign to current node currentNode = nextNode; } //Append the node to be recovered as the next node of the found current node currentNode.next=node; return this; } //Inserts a node as the next node of the current node public void after(Node node) { //Take out the next node as the next node Node nextNext = next; //Take the new node as the next node of the current node this.next=node; //Set the next node as the next node of the new node node.next=nextNext; } //Display all node information public void show() { Node currentNode = this; while(true) { System.out.print(currentNode.data+" "); //Take out the next node currentNode=currentNode.next; //If it is the last node if(currentNode==null) { break; } } System.out.println(); } //Delete next node public void removeNext() { //Take out the next node Node newNext = next.next; //Set the next node as the next node of the current node this.next=newNext; } // Get next node public Node next() { return this.next; } //Get data in node public int getData() { return this.data; } //Is the current node the last node public boolean isLast() { return next==null; } }
Circular linked list
//Circular linked list public class LoopNode { //Node content int data; //Next node LoopNode next=this; public LoopNode(int data) { this.data=data; } //Inserts a node as the next node of the current node public void after(LoopNode node) { //Take out the next node as the next node LoopNode nextNext = next; //Take the new node as the next node of the current node this.next=node; //Set the next node as the next node of the new node node.next=nextNext; } //Delete next node public void removeNext() { //Take out the next node LoopNode newNext = next.next; //Set the next node as the next node of the current node this.next=newNext; } //Get next node public LoopNode next() { return this.next; } //Get data in node public int getData() { return this.data; } }
Double linked list
//Implementation of circular bidirectional linked list public class DoubleNode { //Previous node DoubleNode pre=this; //Next node DoubleNode next=this; //Node data int data; public DoubleNode(int data) { this.data=data; } //Add node public void after(DoubleNode node) { //Original next node DoubleNode nextNext = next; //Take the new node as the next node of the current node this.next=node; //Make the current node the previous node of the new node node.pre=this; //Let the original next node be the next node of the new node node.next=nextNext; //Make the previous node of the original next node a new node nextNext.pre=node; } //Next node public DoubleNode next() { return this.next; } //Previous node public DoubleNode pre() { return this.pre; } //get data public int getData() { return this.data; } }
Stack and queue
Stack
- Stack is a special linear table, and its insertion and deletion operations are only allowed at one end of the linear table. (in and out)
- The end that allows operations is called the Top of the stack, and the end that does not allow operations is called the Bottom of the stack.
- The operation of inserting elements into the stack is called push, and the operation of deleting elements is called Pop.
- A stack without elements is called an empty stack.
- The stack with Sequential Stack storage structure is called Sequential Stack.
- The stack stored in chain structure is called Linked Stack.
Declare Stack interface Stack
//Declare stack interface stack < T > public interface Stack<T>{ public abstract boolean isEmpty(); //Determine whether the stack is empty public abstract void push(T x); //Element x stack public abstract T peek(); //Return stack top element, not out of stack public abstract T pop();0 //Out of the stack, return the top element of the stack }
Sequential stack
public final class SeqStack<t> implements Stack<T>{ private SeqList<T> list; public SeqStack(int length){ //Construct an empty stack with a capacity of length. This. List = new seqlist < T > (length)// Execute the construction method of the sequence table} public seqstack() {this (64);} public Boolean isempty() {return this. List. Isempty();} public void push (t x) {/ / element X is stacked, and empty objects cannot be stacked this.list.insert(x); / / insert element x at the end of the sequence table to automatically expand the capacity} public T peek() {/ / returns the top element of the stack (not out of the stack). If the stack is empty, return null return this.list.get (list. Size() - 1);} public t pop() {/ / returns the top element of the stack. If the stack is empty, return null return list.remove (list. Size() - 1); / / if the stack is not empty, delete the end of the sequence table and return the deleted element}}
Chain stack
public final class LinkedStack<T> implements Stack<T>{ private SingleList<T> list; public LinkedStack(){ this.list = new SingleList<T>(); } public boolean isEmpty(){ return this.list.isEmpty(); } public void push(T x)(){ this.list.add(0, x); } public T peek(){ return this.list.get(0); } public T pop(){ return this.list.remove(0); }}
Convert decimal to binary
public static void main(String[] args) { //Given a decimal number int n=13; // Define an empty stack Deque stack = new LinkedList(); // Convert a decimal number to a binary number int t = n; // Divisor while(t>0) { int mod = t% 2; stack.push(mod); t = t/2; } // Output results System.out.print(n+"---->" ); while(!stack.isEmpty()) { System.out.print(stack.pop()); } }
queue
- Queue is a special linear table. Its insertion and deletion operations are carried out at both ends of the linear table.
- The process of inserting elements into a queue is called Enqueue, and the process of deleting elements is called Dequeue.
- The section allowed to join the team is called the Rear, and the section allowed to leave the team is called the Front.
- A queue without elements is called an empty queue.
- Insert and delete operations are performed at the end of the queue and at the head of the queue respectively. The first element in the queue is always out of the queue. Therefore, the characteristics of the queue are first in first out
public class MyQueue { int[] elements; public MyQueue() { elements=new int[0]; } //Join the team public void add(int element) { // Create a new array int[] newArr = new int[elements.length + 1]; // Copy the elements from the original array to the new array for (int i = 0; i < elements.length; i++) { newArr[i] = elements[i]; } // Put the added element into the new array newArr[elements.length] = element; // Replace old array with new array elements = newArr; } // Out of the team public int poll() { // Take out the 0th element in the array int element = elements[0]; // Create a new array int[] newArr = new int[elements.length-1]; // Copy the elements from the original array to the new array for(int i=0;i<newArr.length;i++) { newArr[i]=elements[i+1]; } // Replace old array with new array elements=newArr; return element; } // Determine whether the queue is empty public boolean isEmpty() { return elements.length==0; }}
Sequential queue
Chain queue
Priority queue
recursion
The programming method of calling the method (function) itself inside a method (function)
Fibonacci sequence
public class TestFebonacci { public static void main(String[] args) { //Fibonacci sequence 0 1 1 2 3 5 8 13 int i = febonacci(7); System.out.println(i); } // Returns the nth item of Fibonacci sequence public static int febonacci(int n) { if (n<0) { throw new IllegalArgumentException("invalid parameter"); } if(n==0 || n==1) { return n; } else { return febonacci(n-2)+febonacci(n-1); } }}
Hanoi Tower problem
public class TestHanoi { public static void main(String[] args) { hanoi(7,'A','B','C'); } /** * @param n There are N plates in total * @ param from Starting column * @ param in Middle column * @ param to Target column * No matter how many plates, there are only two. All the plates above and the bottom plate. */ public static void hanoi(int n,char from,char in,char to) { //Only one plate if(n==1) { System.out.println("the first plate" + from + "move to" + to); // No matter how many plates, there are only two. All the plates above and the bottom plate. } else { // Move all the plates above to the middle position hanoi(n-1,from,to,in); // Move the plate below System.out.println("the" + N + Th plate moves from "+ from +" to "+ to"); // Move all the plates above from the middle position to the target position hanoi(n-1,in,from,to); } }}
algorithm
It is a collection of instructions and a series of operations specified to solve specific problems.
It is a well-defined computable process that takes a data set as input and produces a data combination as output.
characteristic:
- Input: an algorithm should take the information of the problem to be solved as input.
- Output: input the information obtained after processing the corresponding instruction set.
- Feasibility: the algorithm is feasible, that is, each instruction in the algorithm can be implemented and completed in a limited time.
- Finiteness: the number of instructions executed by the algorithm is limited, and each instruction is completed in a limited time, so the whole algorithm can end in a limited time.
- Certainty: for a specific legal input, the corresponding output of the algorithm is unique. That is, when the algorithm starts from a specific input and executes the same instruction set multiple times, the result is always the same.
Basic requirements of algorithm:
- Correctness
- Readability
- Robustness
- Time complexity
- Spatial complexity
Common algorithms
The content of data structure research is how to organize the data according to a certain logical structure, and select an appropriate storage representation method to store the data organized by the logical structure in the memory of the computer. The purpose of algorithm research is to process the data more effectively and improve the efficiency of data operation. The operation of data is defined in the logical structure of data, but the operation is very complex The specific implementation should be carried out on the storage structure.
- Retrieval: retrieval is to find nodes that meet certain conditions in the data structure. Generally, given the value of a field, find nodes with the value of the field.
- Insert: adds a new node to the data structure.
- Delete: removes the specified node from the data structure.
- Update: changes the value of one or more fields of the specified node.
- Sort: rearrange nodes in a specified order, such as increasing or decreasing.
How to measure the advantages and disadvantages of an algorithm?
Time complexity
It refers to the trend that the execution time of the algorithm increases with the increase of the problem scale
During algorithm analysis, 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 and 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)). It represents the growth rate of algorithm execution time and f(n) with the increase of problem scale n The same growth rate is called the asymptotic time complexity of the algorithm, which is called the time complexity, where f(n) is a function of the problem scale n.
Worst time complexity and average time complexity:
The worst-case time complexity is called the worst-case time complexity. Generally, it is not specified, and the time complexity discussed is the worst-case time complexity.
The reason for this is that the time complexity in the worst case is the upper bound of the running time of the algorithm on any input instance, which ensures that the running time of the algorithm will not be longer than any other instance.
In the worst case, the time complexity is T(n)=O(n), which means that the running time of the algorithm cannot be greater than O(n) for any input instance.
Average time complexity refers to the expected running time of the algorithm when all possible input instances occur with equal probability.
- Difficult to calculate
- There are many algorithms with the same complexity in the average case and the worst case
Therefore, the worst time complexity is generally discussed
In order to illustrate the time complexity of the algorithm, O, Ω Θ Symbol
- Worst time complexity, T(n) = O(n^2)
- Best time complexity, T(n) = Ω (n^2)
- Average time complexity, T(n)= Θ (n^2)
Time complexity calculation
There is no need to calculate the time frequency at all. Even if the calculation process still ignores the coefficients of constant, low power and highest power, the following simple method can be adopted;
- Find out the basic statements in the algorithm
- The most frequently executed statement in the algorithm is the basic statement, which is usually the loop body of the innermost loop.
- Calculates the order of magnitude of the number of executions of the base statement
- You only need to calculate the order of magnitude of the number of executions of the basic statement, which means that as long as the highest power in the function of the number of executions of the basic statement is correct,
- All coefficients of the lower and highest powers can be ignored. This can simplify algorithm analysis and focus attention on the most important point: growth rate.
- The time performance of the algorithm is represented by a large O symbol
- Put the order of magnitude of the number of executions of the basic statement into the large O symbol.
Common time complexity levels
- Constant order O(1)
- Logarithmic order O(log ν n)
- Linear order O(n)
- Linear logarithmic order O(n*log ν n)
- Square price O(n) ²)
Space Complexity
The storage capacity of the algorithm includes:
- Space occupied by the program itself
- Space occupied by input data
- Space occupied by auxiliary variables
The space occupied by the input data only depends on the problem itself and has nothing to do with the algorithm. Therefore, only the additional space occupied by auxiliary variables other than the input and program needs to be analyzed.
Space complexity is a measure of the amount of storage space temporarily occupied by an algorithm during operation. It is generally given in order of magnitude as a function of problem scale n, which is recorded as:
S(n) = O(g(n))
int fun(int n){ //N is the problem scale int i, J, K, s; s = 0; for (I = 0; I < = n; I + +) {for (J = 0; J < = I; j + +) {for (k = 0; K < = J; K + +) {S + +;}}} return (s);}
No matter how the scale of the problem changes, the memory space required for the operation of the algorithm is a fixed constant, and the complexity of the algorithm space is:
S(n) = O(1)
sort
Sorting is to rearrange the data elements in ascending (or descending) order according to the size of the specified keyword value.
Eight common sorting algorithms:
-
Exchange sort
- Bubble sorting
- Quick sort
-
Insert sort
- Direct insert sort
- Shell Sort
-
Select sort
- Direct selection sort
- Heap sort+
-
Merge sort
Exchange sort
Bubble sorting
Compare the size of two adjacent elements. If they are in reverse order, they will be exchanged. If they are sorted in ascending order, the largest element in the data sequence will be exchanged to the last position in each pass, just like bubbles emerging from the water.
public class BubbleSort { public static void main(String[] args) { int[] arr=new int[] {5,7,2,9,4,1,0,5,7}; System.out.println(Arrays.toString(arr)); bubbleSort(arr); System.out.println(Arrays.toString(arr)); } //Bubble sorting /** * 5,7,2,9,4,1,0,5,7 A total of length-1 rounds need to be compared * 5,7,2,9,4,1,0,5,7 * 5,2,7,9,4,1,0,5,7 * 5,2,7,4,1,0,5,7,9 * 2,5 */ public static void bubbleSort(int[] arr) { // Control the total number of rounds for(int i=0;i<arr.length-1;i++) { // Controls the number of comparisons for(int j=0;j<arr.length-1-i;j++) { if(arr[j]>arr[j+1]) { int temp=arr[j]; arr[j]=arr[j+1]; arr[j+1]=temp; } } } }}
Quick sort
Select an element in the data sequence as the reference value, and start alternately from both ends of the data sequence. Exchange the elements less than the reference value to the front of the sequence, and the elements with large and reference value to the back of the sequence. The position before the two becomes the final position of the reference value. At the same time, the sequence is divided into two subsequences, and then the two subsequences are processed respectively The rows are sorted quickly until the subsequence length is 1.
public class QuickSort { public static void main(String[] args) { int[] arr = new int[] {3,4,6,7,2,7,2,8,0,9,1}; quickSort(arr,0,arr.length-1); System.out.println(Arrays.toString(arr)); } public static void quickSort(int[] arr,int start,int end) { if(start<end && start>=0 && end>=0 && start<arr.length && end<arr.length) { //Take the 0th number in the array as the standard number int stard=arr[start]; // The subscript of the record to be sorted int low=start; int high=end; // Loop to find a number larger than the standard number and a number smaller than the standard number while(low<high) { // The number on the right is larger than the standard number while(low<high && stard<=arr[high]) { high--; } // Replace the number on the left with the number on the right arr[low]=arr[high]; // If the number on the left is smaller than the standard number while(low<high && arr[low]<=stard) { low++; } arr[high]=arr[low]; } // Assign the standard number to the element in the low position arr[low]=stard; // Handle all the small numbers quickSort(arr, start, low); // Handle all large numbers quickSort(arr, low+1, end); } }}
Insert sort
Each time, an element is inserted into the sorted subsequence in front of it according to the size of its keyword value, and repeated in turn until all elements are inserted.
Direct insert sort
public class InsertSort { public static void main(String[] args) { int[] arr = new int[] {5,7,2,8,5,9,1,0}; insertSort(arr); System.out.println(Arrays.toString(arr)); } //Insert sort public static void insertSort(int[] arr) { // Traverse all numbers for(int i=1;i<arr.length;i++) { // If the current number is smaller than the previous one// if(arr[i]<arr[i-1]) { // Save the current traversal number int temp=arr[i]; int j; // Traverse all the numbers before the current number for(j=i-1;j>=0&&temp<arr[j];j--) { // Assign the previous number to the next number arr[j+1]=arr[j]; } // Assign a temporary variable to the latter element that does not meet the condition arr[j+1]=temp;// } } }}
Shell Sort
Also known as reduced incremental sorting
A data sequence is divided into several groups, each of which is separated by a certain distance (called increment) The initial value of increment is usually half of the length of data sequence, and then the increment of each trip is halved, and the final value is 1. As the increment gradually decreases, the number of groups also decreases, the number of elements in the group increases, and the data sequence is close to order.
public class ShellSort { public static void main(String[] args) { int[] arr = new int[] { 3, 5, 2, 7, 8, 1, 2, 0, 4, 7, 4, 3, 8 }; System.out.println(Arrays.toString(arr)); shellSort(arr); System.out.println(Arrays.toString(arr)); } public static void shellSort(int[] arr) { int k = 1; // Traverse all steps for (int d = arr.length / 2; d > 0; d /= 2) { // Traverse all elements for (int i = d; i < arr.length; i++) { // Traverse all elements in this group for (int j = i - d; j >= 0; j -= d) { // If the current element is larger than the element after adding the step size if (arr[j] > arr[j + d]) { int temp = arr[j]; arr[j] = arr[j + d]; arr[j + d] = temp; } } } System.out.println("The first" + k + "Secondary sorting result" + Arrays.toString(arr)); k++; } } }
Select sort
Direct selection sort
In the first pass, select the element with the smallest / largest keyword from the data sequence of n elements and put it in the front / back position. In the next pass, select the smallest / largest element from the N-1 elements and put it in the front / back position. And so on. After n-1 passes, the sorting is completed.
// Directly select and sort public class SelectSort{ public static void main(String[] args) { int[] arr = new int[] {3,4,5,7,1,2,0,3,6,8}; selectSort(arr); System.out.println(Arrays.toString(arr)); } // Select sort public static void selectSort(int[] arr) { // Traverse all numbers for(int i=0;i<arr.length;i++) { int minIndex=i; // Compare the current traversal number with all subsequent numbers in turn, and record the minimum number subscript for(int j=i+1;j<arr.length;j++) { // If the number compared later is smaller than the minimum number recorded if(arr[minIndex]>arr[j]) { // Record the subscript of the smallest number minIndex=j; } } // If the minimum number is inconsistent with the subscript of the current traversal number, it indicates that the number with the subscript minindex is smaller than the current traversal number if(i!=minIndex) { int temp=arr[i]; arr[i]=arr[minIndex]; arr[minIndex]=temp; } } }}
Heap sort
https://www.cnblogs.com/chengxiao/p/6129630.html
The basic idea of heap sorting is to construct the sequence to be sorted into a large top heap. At this time, the maximum value of the whole sequence is the root node at the top of the heap. Exchange it with the last element, and the end is the maximum value. Then reconstruct the remaining n-1 elements into a heap, so as to get the sub small value of n elements. If you execute it repeatedly, you can get an ordered sequence
// Heap sorting public class HEAPSORT {public static void main (string [] args) {int [] arr = New Int [] {9, 6, 8, 7, 0, 1, 10, 4, 2}; HEAPSORT (ARR); system.out.println (arrays. ToString (ARR));} public static void HEAPSORT (int [] ARR) {/ / the start position is the last non leaf node, that is, the parent node of the last node int start = (arr.length - 1) / 2; / / adjust to the large top heap for (int i = start; I > = 0; I --) {maxheap (arr, arr.length, I);} //First swap the position of the 0th number in the array and the last number in the heap, and then process the previous as a large top heap for (int i = arr.length - 1; I > 0; I --) {int temp = arr [0]; arr [0] = arr [i]; arr [i] = temp; maxheap (arr, I, 0);}} public static void maxheap (int [] arr, int size, int index) {/ / left child node int leftNode = 2 * index + 1; / / right child node int rightnode = 2 * index + 2; int max = index; / / compare with the two child nodes to find the largest node if (leftnode < size & & arr [leftnode] > arr [Max]) {max = leftnode;} if (rightnode < size & & arr [rightnode] > arr [Max]) {max = rightnode;} / / exchange position if (max! = index) {int temp = arr [index]; arr [index] = arr [Max]; arr [Max] = temp; / / after exchanging positions, the previously arranged heap may be destroyed. Therefore, the previously arranged heap needs to be readjusted maxHeap(arr, size, max);}}}
Merge sort
public class MergeSort { public static void main(String[] args) { int[] arr = new int[] {1,3,5,4,2,6,8,10}; System.out.println(Arrays.toString(arr)); mergeSort(arr, 0, arr.length-1); System.out.println(Arrays.toString(arr)); } // Merge sort public static void mergeSort(int[] arr,int low,int high) { int middle=(high+low)/2; if(low<high) { // Process left mergeSort(arr, low, middle); // Process right mergeSort(arr, middle+1, high); // Merge merge(arr,low,middle,high); } } public static void merge(int[] arr,int low,int middle, int high) { // Used to store the merged temporary array int[] temp = new int[high-low+1]; // Record the subscripts that need to be traversed in the first array int i=low; // Record the subscripts that need to be traversed in the second array int j=middle+1; // Subscripts stored in temporary array of user records int index=0; // Traverse the two arrays, take out the small numbers and put them into the temporary array while(i<=middle && j<=high) { // If the data of the first group is smaller if(arr[i]<=arr[j]) { // Put small data into a temporary array temp[index]=arr[i]; // Move the subscript back one bit i++; } else { temp[index]=arr[j]; j++; } index++; } // Processing redundant data while(j<=high) { temp[index]=arr[j]; j++; index++; } while(i<=middle) { temp[index]=arr[i]; i++; index++; } // Flush the data in the temporary array into the original array for(int k=0;k<temp.length;k++) { arr[k+low]=temp[k]; } }}
Cardinality sort
// Cardinality sort public class RadixSort{ public static void main(String[] args) { int[] arr = new int[] {23,6,189,45,9,287,56,1,798,34,65,652,5}; radixSort(arr); System.out.println(Arrays.toString(arr)); } public static void radixSort(int[] arr) { // The largest tree in the storage array int max=Integer.MIN_VALUE; for(int i=0;i<arr.length;i++) { if(arr[i]>max) { max=arr[i]; } } // How many digits is the maximum number of calculations int maxLength = (max+"").length(); // An array used to temporarily store data int[][] temp = new int[10][arr.length]; // Used to record the number of numbers stored in the corresponding array in temp int[] counts = new int[10]; // The number of comparisons is determined according to the maximum length for(int i=0,n=1;i<maxLength;i++,n*=10) { // Calculate the remainder of each number separately for(int j=0;j<arr.length;j++) { // Calculate remainder int ys = arr[j]/n%10; // Put the currently traversed data into the specified array temp[ys][counts[ys]] = arr[j]; // Number of records counts[ys]++; } // Record the location where the retrieved element needs to be placed int index=0; // Take out the numbers for(int k=0;k<counts.length;k++) { // The number of current remainder records in the array of record quantity is not 0 if(counts[k]!=0) { // Loop out elements for(int l=0;l<counts[k];l++) { // Extract element arr[index] = temp[k][l]; // Record the next position index++; } // Set the quantity to 0 counts[k]=0; } } } }}
Queue implementation of Radix sorting
public class RadixQueueSort { public static void main(String[] args) { int[] arr = new int[] {23,6,189,45,9,287,56,1,798,34,65,652,5}; radixSort(arr); System.out.println(Arrays.toString(arr)); } public static void radixSort(int[] arr) { // The largest tree stored in the array int max = integer.min_value; for (int i = 0; I < arr.length; I + +) {if (arr [i] > max) {max = arr [i];}} / / calculate the maximum number of digits int maxLength = (max+"").length(); / / use the array myqueue [] temp = new myqueue with the queue storing temporary data [10] ; / / assign a value to the queue array for (int i = 0; I < temp. Length; I + +) {temp [i] = new myqueue();} / / determine the number of comparisons according to the maximum length for (int i = 0, n = 1; I < MaxLength; I + +, n * = 10) {/ / calculate the remainder of each number for (int j = 0; J < arr.length; j + +) {/ / calculate the remainder int ys = arr[j]/n%10; / / put the currently traversed data into the specified queue temp[ys].add(arr[j]);} / / record the position where the retrieved element needs to be placed int index=0; / / get the number for (int k = 0; K < temp. Length; K + +) {/ / the currently traversed queue is not empty while(!temp[k].isEmpty()) {/ / take out the element arr[index] = temp[k].poll(); / / record the next position index + +;}}}}}
tree
A Tree is a finite set composed of n (n > = 0) nodes (the elements in the Tree are usually called nodes). A Tree with n=0 is called an empty Tree; a Tree with n > 0 T is composed of the following two conditions:
- There is a special node called root node. It has only successor nodes and no precursor nodes.
- Other nodes except the root node are divided into m (0 ≤ m < n) disjoint sets T0, T1,..., Tm-1, in which each set Ti (0 ≤ I < m) also has a tree structure, which is called the subtree of the root
Tree terms
-
Parents, children and brothers
- In a tree, the root node of a node's subtree is called a child node; In contrast, the node is the parent node of its child node.
- Multiple nodes with the same parent node are called sibling nodes.
- The ancestor of a node refers to its parent node, as well as its parent node, up to the root node. The Descendant of a node refers to all its child nodes and children's child nodes.
-
degree
- The degree of a node is the tree of the subtree owned by the node.
- A node with a degree of 0 is called a leaf node, also known as a terminal node; Other nodes in the tree except leaf nodes are called branch nodes, also known as non leaf nodes or non terminal nodes.
- The degree of a tree refers to the maximum degree of each node in the tree.
-
Node hierarchy and tree height
- The level attribute of a node reflects the hierarchical position of the node in the tree.
- The height or depth of the tree is the maximum number of layers of nodes in the tree.
-
Edge, path, diameter
- Let X node in the tree be the parent node of Y node, and the ordered pair (X,Y) is called the branch connecting the two nodes, also known as the edge
- Let (X0,X1,..., Xk) (0 ≤ K < n) be a sequence composed of nodes in the tree, and (Xi, Xi+1) are all edges in the tree, then it is called a path of the sequence X0 to Xk. The path length is the number of edges on the path.
- The diameter of the binary tree refers to the longest path from the root to the leaf node. The path length of the diameter is the height of the binary tree - 1
-
Disordered tree
In the definition of number, there is no order between the subtrees of nodes, which can call the position. It is called unordered tree, which is called number for short. If the subtree of a node is ordered from left to right and cannot exchange positions, it is called an ordered tree. -
forest
Forest is a collection of m (m > = 0) disjoint trees. Adding a root node to the forest becomes a tree, and deleting the root node of the tree becomes a forest.
Binary tree
Binary Tree
A binary tree is a finite set of n (n ≥ 0) nodes. When n=0, it is called an empty binary tree; n> The binary tree of 0 is composed of a root node and two disjoint sub binary trees called left subtree and right subtree respectively.
Properties of binary tree
Property 1: the maximum number of nodes on layer I of binary tree is 2{i-1} (i≥1).
Property 2: a binary tree with height K has at most 2{k}-1 nodes (K ≥ 1).
Property 3: in any binary tree, if the number of terminal nodes is n0 and the number of nodes with degree 2 is n2, then n0=n2+1.
Property 4: the height of a binary tree containing N nodes is at least log2 (n+1).
Full binary tree: all leaf nodes are in the last layer, and the total number of nodes is 2^n - 1
Complete binary tree: all leaf nodes are in the last or penultimate layer, and the leaf nodes of the last layer are continuous on the left and the leaf nodes of the penultimate node are continuous on the right
Traversal of binary tree
First root order: access the root node, traverse the left subtree and the right subtree.
Middle root order: traverse the left subtree, access the root node, and traverse the right subtree.
Post root order: traverse the left subtree, traverse the right subtree, and access the root node.
// Binary tree public class binarytree {treenode root; / / set the root node public void setroot (treenode root) {this. Root = root;} / / create a public treenode getroot() {return root;} public void frontshow() {if (root! = null) {root. Frontshow();}} public void midshow() {if (root!=null) { root.midShow(); } } public void afterShow() { if(root!=null) { root.afterShow(); } } public TreeNode frontSearch(int i) { return root.frontSearch(i); } public void delete(int i) { if(root.value==i) { root=null; }else { root.delete(i); } }}
// Tree node public class TreeNode {/ / node weight int value; / / left son TreeNode leftNode; / / right son treenode rightnode; public treenode (int value) {this. Value = value;} / / set left son public void setleftnode (TreeNode leftNode) {this. Leftnode = leftnode;} / / set right son public void setrightnode (treenode rightnode) {this.rightnode = rightnode;} / / traverse public void frontShow() {/ / traverse the contents of the current node System.out.println(value); / / left node if (leftnode! = null) {leftnode. Frontshow();} / / right node if (rightnode! = null) {rightnode. Frontshow();}} //Traverse public void midShow() {/ / left child node if (leftnode! = null) {leftnode. Midshow();} / / current node System.out.println(value); / / right child node if (rightnode! = null) {rightnode. Midshow();} / / traverse public void afterShow() {/ / left child node if (leftnode! = null) {leftnode. Aftershow();} / / right child node if (rightnode! = null) {rightnode. Aftershow();} / / current node System.out.println(value);} / / find public treenode frontsearch (int i) {treenode target = null in the preamble. / / compare the value of the current node if (this. Value = = I) {return this; / / the value of the current node is not the node to be found}else {/ / find the left child if (leftnode! = null) {/ / it may or may not be found. If not, the target is still null. Target = leftnode. Frontsearch (I);} //If it is not empty, it means that if (target! = null) {return target;} / / find the right son if (rightnode! = null) {target = rightnode. Frontsearch (I);}} return target;} / / delete a subtree public void delete (int i) {treenode parent = this; / / judge the left son if (parent. Leftnode! = null & & parent. Leftnode. Value = = I) {parent. Leftnode = null; return;} / / judge the right son if (parent. Rightnode! = null & & parent. Rightnode. Value = = I) {parent. Rightnode = null; return;} //Recursively check and delete the left child parent = leftnode; if (parent! = null) {parent. Delete (I);} / / recursively check and delete the right child parent = rightnode; if (parent! = null) {parent. Delete (I);}}}
test
public class TestBinaryTree { public static void main(String[] args) { // Create a tree BinaryTree binTree = new BinaryTree()// Create a root node TreeNode root = new TreeNode(1)// Assign the root node to the tree binTree.setRoot(root)// Create a left TreeNode rootL = new TreeNode(2)// Set the newly created node as the root.setLeftNode(rootL) of the root node// Create a right TreeNode rootR = new TreeNode(3)// Set the newly created node as the root.setRightNode(rootR) of the root node// Create two child nodes rootl.setleftnode (New treenode (4)) for the left node of the second layer; rootL.setRightNode(new TreeNode(5)); // Create two child nodes rootr.setleftnode (New treenode (6)) for the right node of the second layer; rootR.setRightNode(new TreeNode(7)); // Pre order traversal tree bintree. Frontshow(); System.out.println("==============="); // Traverse bintree. Midshow() in middle order; System.out.println("==============="); // After traversing bintree. Aftershow(); System.out.println("==============="); // Preorder search treenode result = bintree.frontsearch (5); System.out.println(result); System.out.println("==============="); // Delete a subtree bintree. Delete (4); binTree.frontShow(); }}
Sequential stored binary tree
Binary tree mainly adopts chain storage structure, and sequential storage structure is only applicable to complete binary tree (full binary tree).
Properties of sequentially stored binary trees
Traversal of sequentially stored binary tree
public class ArrayBinaryTree { int[] data; public ArrayBinaryTree(int[] data) { this.data=data; } public void frontShow() { frontShow(0); } // Traverse public void frontshow (int index) {if (data = = null | data. Length = = 0) {return;} / / traverse the contents of the current node system.out.println (data [index]); / / 2 * index + 1: process the left subtree if (2 * index + 1 < data. Length) {frontshow (2 * index + 1);} / / 2 * index + 2: process the right subtree if (2*index+2 < data.length) { frontShow(2*index+2); } }}
public class TestArrayBinaryTree { public static void main(String[] args) { int[] data = new int[] {1,2,3,4,5,6,7}; ArrayBinaryTree tree = new ArrayBinaryTree(data); //Pre order traversal of tree.frontShow();}}
Clue binary tree
For a binary tree with n nodes, there are n+1 empty chain domains in the binary chain storage structure. These empty chain domains are used to store the pointers of the precursor nodes and successor nodes of the node in a certain traversal order. These pointers are called clues, and the binary tree with clues is called clue binary tree.
The process of traversing a binary tree in a certain order and adding clues is called cueing. Binary trees that are cued in the order of first / middle / second root traversal are called first / middle / second order cued binary trees respectively
Precursor node: a binary tree is traversed in middle order, and the order after traversal. The previous node of the current node is the precursor node of the node;
Successor node: a binary tree is traversed in middle order. The order after traversal. The next node of the current node is the successor node of the node;
For example, a complete binary tree (1,2,3,4,5,6,7) is traversed in the middle order as follows: (4,2,5,1,6,3,7), the precursor node of node 1 is 5 and the successor node is 6
Now point the null pointer field of a node to the predecessor and successor of the node. The definition rules are as follows:
If the left subtree of a node is empty, the left child pointer of the node points to its predecessor node.
If the right subtree of a node is empty, the right child pointer of the node points to its successor node.
Implementation of clue binary tree
/** * Binary linked list node of clue binary tree */public class ThreadedNode { // Node weight int value; / / left son ThreadedNode leftNode; / / right son ThreadedNode rightNode; / / identify pointer type int lefttype = 0; int righttype = 0; public threadednode (int value) {this. Value = value;} / / set left son public void setleftnode (ThreadedNode leftNode) {this.leftnode = leftnode;} / / set the right son public void setrightnode (ThreadedNode rightNode) {this.rightnode = rightnode;}}
// Clue binary tree public class ThreadedBinaryTree {/ / the root node ThreadedNode root; / / used to temporarily store the precursor node ThreadedNode pre = null; / / set the root node public void setroot (ThreadedNode root) {this. Root = root;} / / in order cued binary tree public void threadnodes() {threadnodes (root);} Public void threadnodes (threadednode node) {/ / if the current node is null, directly return if (node = = null) {return;} / / process the left subtree threadNodes(node.leftNode); / / process the precursor node if (node.leftNode == null) {/ / make the left pointer of the current node point to the predecessor node.leftNode = pre; / / change the type of the left pointer of the current node node. node.leftType = 1;} / / process the right pointer of the predecessor node. If the right pointer of the predecessor node is null (no lower right subtree) if (pre! = null & & pre.rightnode = = null) {/ / make the right pointer of the precursor node point to the current node pre.rightNode = node; / / change the right pointer type of the precursor node pre.rightType = 1;} / / for each node processed, the current node is the precursor node of the next node pre = node; / / process the right subtree threadNodes(node.rightNode);} //Get the root node public threadednode getroot() {return root;}}
Traversal clue binary tree
// Traverse the thread binary tree public void threadinterate() {/ / used to temporarily store the traversing node threadednode node = root; while (node! = null) {/ / loop to find the first node while (node. Lefttype = = 0) {node = node. Leftnode;} / / print the value of the current node System.out.println(node.value) ; / / if the right pointer of the current node points to the successor node, the successor node may also include the successor node, while (node. Righttype = = 1) {node = node.rightNode; System.out.println(node.value);} / / replace the traversed node node = node.rightNode;}}
test
public class TestThreadedBinaryTree { public static void main(String[] args) { //Create a tree ThreadedBinaryTree binTree = new ThreadedBinaryTree()// Create a root node ThreadedNode root = new ThreadedNode(1)// Assign the root node to the tree binTree.setRoot(root)// Create a left node ThreadedNode rootL = new ThreadedNode(2)// Set the newly created node as the root.setLeftNode(rootL) of the root node// Create a right node ThreadedNode rootR = new ThreadedNode(3)// Set the newly created node as the root.setRightNode(rootR) of the root node// Create two child nodes rootl.setleftnode (New threadednode (4)) for the left node of the second layer; ThreadedNode fiveNode = new ThreadedNode(5); rootL.setRightNode(fiveNode); // Create two child nodes rootr.setleftnode (New threadednode (6)) for the right node of the second layer; rootR.setRightNode(new ThreadedNode(7)); // Middle order traversal of the tree bintree. Midshow(); System.out.println("==============="); // Binary tree bintree. Threadnodes(); binTree.threadIterate(); }}
huffman tree
Huffman, also known as optimal binary tree: it is the binary tree with the smallest weighted path length among all binary trees composed of n weighted leaf nodes.
Path length: in a path, the path length should be increased by 1 for each node. For example, in a tree, if the number of layers of the root node is specified as 1, the path length from the root node to the i-th layer node is i - 1. The path length from root node to node c in the figure is 3.
Weighted path length of leaf node: refers to the product of the path length from the root node to the node and the weight of the node. For example, the weighted path length of node b in the figure is 2 * 5 = 10.
Weighted path length (WPL) of tree: the sum of weighted path lengths of all leaf nodes in the tree. Usually referred to as "WPL". As shown in the figure, the weighted path length of this tree is:
WPL = 7 * 1 + 5 * 2 + 2 * 3 + 4 * 3
When constructing a Huffman tree, to minimize the weighted path length of the tree, we only need to follow one principle: the greater the weight, the closer the node is to the tree root.
Constructing Huffman tree
- Two minimum weights are selected from the n weights, and the corresponding two nodes form a new binary tree, and the weight of the root node of the new binary tree is the sum of the weight of the left and right children;
- Delete the two smallest weights from the original n weights, and add the new weights to the ranks of n – 2 weights, and so on;
- Repeat 1 and 2 until all nodes form a binary tree, which is the Huffman tree.
public class Node implements Comparable<Node> { int value; Node left; Node right; public Node(int value) { this.value = value; } @Override public int compareTo(Node o) { return -(this.value - o.value); } @Override public String toString() { return "TreeNode [value=" + value + "]"; }}
public class TestHuffmanTree { public static void main(String[] args) { int[] arr = {3, 7, 8, 29, 5, 11, 23, 14}; Node node = createHuffmanTree(arr); System.out.println(node); } // Create Huffman tree public static Node createHuffmanTree(int[] arr) { // First, use all the elements in the array to create several binary trees (only one node) List<Node> nodes = new ArrayList<>(); for (int value : arr) { nodes.add(new Node(value)); } // Cyclic processing, while (nodes.size() > 1) { // sort Collections.sort(nodes); // Take out the two binary trees with the smallest weight // Take out the binary tree with the smallest weight Node left = nodes.get(nodes.size() - 1); // Take out the binary tree with the smallest weight Node right = nodes.get(nodes.size() - 2); // Create a new binary tree Node parent = new Node(left.value + right.value); // Remove the two binary trees nodes.remove(left); nodes.remove(right); // Put it into the original binary tree set nodes.add(parent); } return nodes.get(0); }}
Huffman coding
Implementation steps:
- Count and sort characters
- Create Huffman tree
- Create Huffman coding table
- code
/** * Huffman coding compression method * * @ param bytes * @ return */private static byte[] huffmanZip(byte[] bytes) { // First count the number of occurrences of each byte and put it into a collection list < node > nodes = getnodes (bytes)// Create a Huffman tree node tree = createhuffman tree (nodes)// Create a Huffman code table map < byte, string > huffcodes = getcodes (tree)// Code byte [] B = zip (bytes, huffcodes); return b;}/** * Convert byte array to node set * * @ param bytes * @ return */ Private static list < node > getnodes (byte [] bytes) {list < node > nodes = new ArrayList < > (); / / store the number of occurrences of each byte. Map < byte, integer > counts = new HashMap < > (); / / count the number of occurrences of each byte. For (byte B: bytes) {integer count = counts.get (b); if (count = = null) {counts.put (B, 1) ;} else {counts. Put (B, count + 1);}} / / convert each key value pair into a node object for (entry < byte, integer > entry: counts. Entryset()) {nodes. Add (new node (entry. Getkey(), entry. Getvalue());} return nodes;}/** * Create Huffman tree * * @ param nodes * @ return */ Private static node createhuffmantree (list < node > nodes) {while (nodes. Size() > 1) {/ / sort Collections.sort(nodes); / / take out the two binary trees with the lowest weight, node left = nodes.get (nodes. Size() - 1); node right = nodes.get (nodes. Size() - 2); / / create a new binary tree, Node parent = new Node(null, left.weight + right.weight); / / set the two binary trees as the subtrees of the newly created binary tree, parent.left = left; parent.right = right; / / delete nodes.remove (left); nodes.remove (right); / / put the newly created binary tree into the collection nodes.add (parent);} return nodes. Get (0);} / / used for temporary storage path static StringBuilder sb = new StringBuilder(); / / used for storage of Huffman code static map < byte, string > huffcodes = new HashMap < > ()/** * The Huffman code is obtained according to the Huffman tree * * @ param tree * @ return */ private static Map<Byte, String> getCodes(Node tree) { if (tree == null) { return null; } getCodes(tree.left, "0", sb); getCodes(tree.right, "1", sb); return huffCodes;}private static void getCodes(Node node, String code, StringBuilder sb) { StringBuilder sb2 = new StringBuilder(sb); sb2.append(code); if (node.data == null) { getCodes(node.left, "0", sb2); getCodes(node.right, "1", sb2); } else { huffCodes.put(node.data, sb2.toString()); }}/** * Huffman coding * * @ param bytes * @ param huffCodes * @ return */ Private static byte [] zip (byte [] bytes, map < byte, string > huffcodes) {StringBuilder sb = new stringbuilder(); / / process the byte array to be compressed into a binary string for (byte B: bytes) {sb.append (huffcodes. Get (b));} / / define the length int len; if (sb. Length()% 8 = = 0) {len = sb. Length() / 8;} Else {length = sb. Length() / 8 + 1;} / / used to store the compressed byte [] by = new byte [len]; / / record the position of the new byte. Int index = 0; for (int i = 0; I < sb. Length(); I + = 8) {string strbyte; if (I + 8 > sb. Length()) {strbyte = sb. Substring (I);} else {strbyte = sb. Substring (I);} strstring (i, i + 8); } byte byt = (byte) Integer.parseInt(strByte, 2); by[index] = byt; index++; } return by;}
Huffman decoding
/** * Decode using the specified Huffman encoding table * * @ param huffCodes * @param bytes * @return */private static byte[] decode(Map<Byte, String> huffCodes, byte[] bytes) { StringBuilder sb = new StringBuilder(); //Convert the byte array to a binary string for (int i = 0; I < bytes. Length; I + +) {byte B = bytes [i]; / / whether it is the last. Boolean flag = (I = = bytes. Length - 1); sb. Append (byte tobitstr (! Flag, b));} //Decode the string according to the specified Huffman encoding. / / exchange the Huffman encoded key value pairs. Map < string, byte > map = new HashMap < > (); for (map. Entry < byte, string > entry: huffcodes. Entryset()) {map. Put (entry. Getvalue(), entry. Getkey());} / / create a set for storing byte list < byte > List = new ArrayList < > () ; / / process the string for (int i = 0; I < sb. Length();) {int count = 1; Boolean flag = true; byte B = null; / / intercept a byte while (flag) {string key = sb.substring (I, I + count); b = map.get (key); if (b = = null) {count + +;} else {flag = false;} }List. Add (b); I + = count;} / / convert the set to an array byte [] B = new byte [list. Size()]; for (int i = 0; I < b.length; I + +) {B [i] = list. Get (I);} return B;} private static string bytetobitstr (boolean flag, byte b) {int temp = B; if (flag) {temp | = 256;} string STR = integer.tobinarystring (Temp) ; if (flag) { return str.substring(str.length() - 8); } else { return str; }}
Compressed file
/** * Compressed file * * @ param src * @param dst * @throws IOException */private static void zipFile(String src, String dst) throws IOException { //Create an input stream InputStream is = new FileInputStream(src); / / create a byte array with the same size as the file pointed to by the input stream byte[] b = new byte[is.available()]; / / read the file content is. Read (b); is. Close(); / / use Huffman coding to encode byte[] byteZip = huffmanZip(b) ; / / output stream OS = new fileoutputstream (DST); objectoutputstream OOS = new objectoutputstream (OS); / / write the compressed byte array to the file oos.writeObject(byteZip); / / write the Huffman code table to the file oos.writeobject (huffcodes); OOS. Close(); OS. Close();}
Unzip file
/** * Decompression of files * * @ param src * @param dst * @throws Exception */private static void unZip(String src, String dst) throws Exception { //Create an input stream InputStream is = new FileInputStream (SRC); ObjectInputStream ois = new ObjectInputStream(is); // Read byte array byte[] b = (byte[]) ois.readObject()// Read Huffman code table map < byte, string > codes = (map < byte, string >) ois. Readobject(); ois.close(); is.close(); // Decode byte[] bytes = decode(codes, b)// Create an output stream OutputStream os = new FileOutputStream(dst)// Write out the data OS. Write (bytes); os.close();}
test
public class TestHuffmanCode { public static void main(String[] args) { String msg = "can you can a can as a can canner can a can."; byte[] bytes = msg.getBytes(); //Huffman coding compression byte[] b = huffmanZip(bytes)// Decode using Huffman encoding byte [] newbytes = decode (huffcodes, b); System.out.println(new String(newBytes)); String src = "1.bmp"; String dst = "2.zip"; try { zipFile(src, dst); } catch (IOException e) { e.printStackTrace(); } try { unZip("2.zip", "3.bmp"); } catch (Exception e) { e.printStackTrace(); } }}
Binary sort tree
Binary Sort Tree or an empty tree; Or a binary tree with the following properties:
- Elements are based on keywords. Each node can be compared with the same size, and the keywords of each element are different from each other.
- For each node, all node elements on the left subtree (not empty) are smaller than the node, and all node elements on the right subtree (not empty) are larger than the node.
- The left and right subtrees of each node are also binary sort trees
Create a binary sort tree & add nodes
public class Node { int value; Node left; Node right; public Node(int value) { this.value = value; } /** * Add node * * @ param node to subtree */ public void add(Node node) { if (node == null) { return; } // Judge whether the value of the incoming node is larger or smaller than the value of the root node of the current subtree. / / the added node is smaller than the value of the current node if (node. Value < this. Value) {/ / if the left node is empty if (this. Left = = null) {this. Left = node; / / if it is not empty} else {this. Left. Add (node); } } else { if (this.right == null) { this.right = node; } else { this.right.add(node); } } } /** * Medium order traversal * * @ param node */ public void midShow(Node node) { if (node == null) { return; } midShow(node.left); System.out.println(node.value); midShow(node.right); }}
// Binary sort tree public class binarysorttree {node root; / * * * add node * * @ param node * / public void add (node) {/ / if it is an empty tree if (root = = null) {root = node;} else {root. Add (node);}}/** * Middle order traverses the binary sort tree, from small to large */ public void midShow() { if (root != null) { root.midShow(root); } }}
Find node
Node class/** * Find node * * @ param value */public Node search(int value) { if (this.value == value) { return this; } else if (value < this.value) { if (left == null) { return null; } return left.search(value); } else { if (right == null) { return null; } return right.search(value); }}
BinarySortTree class/** * Node lookup * * @ param value * @return */public Node search(int value) { if (root == null) { return null; } else { return root.search(value); }}
Delete Vertex
/** * Search parent node * * @ param value * @return */public Node searchParent(int value) { if ((this.left != null && this.left.value == value) || (this.right != null && this.right.value == value)) { return this; } else { if (this.value > value && this.left != null) { return this.left.searchParent(value); } else if (this.value < value && this.right != null) { return this.right.searchParent(value); } return null; }}
/** * Delete node * * @ param value */public void delete(int value) { if (root == null) { return; } else { //Find the Node target = search(value); / / if there is no node if (target = = null) {return;} / / find its parent node node Node parent = searchParent(value); / / the node to be deleted is the leaf node if (target. Left = = null & & target. Right = = null) {/ / the node to be deleted is the left child node of the parent node if (parent. Left. Value = = value) {parent. Left = null; / / the node to be deleted is the right child node of the parent node} else {parent. Right = null;} / / the node to be deleted has two child nodes} else if (target. Left! = null & & target. Right! = null) {/ / delete the node with the smallest value in the right subtree and get the value int min = deleteMin(target.right); / / replace the value target.value = min in the target node. / / the node to be deleted has a left child node or a right child node} else {/ / has a left child node if (target. Left! = null) {/ / the node to be deleted is the left child node of the parent node if (parent. Left. Value = = value) {parent. Left = target. Left; / / the node to be deleted is the right child node of the parent node} else {parent. Right = target. Left;} / / there are right child nodes} Else {/ / the node to be deleted is the left child node of the parent node if (parent. Left. Value = = value) {parent. Left = target. Right; / / the node to be deleted is the right child node of the parent node} else {parent. Right = target. Right;}}}}} }/*** delete the smallest node in a tree * * @ param node * @ return * / private int deletemin (node node) {node target = node; / / recursively find while (target. Left! = null) {target = target. Left;} / / delete the smallest node (target. Value); return target. Value;} /*** search parent node * * @ param value * @ return * / public node searchparent (int value) {if (root = = null) {return null;} else {return root.searchparent (value);}}
AVL tree
In order to reduce the height of binary sort tree and improve search efficiency, two former Soviet mathematicians proposed a highly balanced binary sort tree in 1962, which is called balanced binary tree (also known as AVL tree).
Balanced binary tree is either an empty binary tree or a binary sort tree with the following properties: 1. Its left subtree and right subtree are balanced binary trees; 2. The absolute value of the height difference between the left subtree and the right subtree does not exceed 1.
Constructing single rotation of balanced binary tree
public class Node { int value; Node left; Node right; public Node(int value) { this.value = value; } /** * Returns the height of the current node * * @ return */ public int height() { return Math.max(left == null ? 0 : left.height(), right == null ? 0 : right.height()) + 1; } /** * Get the height of the left subtree * * @ return */ public int leftHeight() { if (left == null) { return 0; } return left.height(); } /** * Get the height of the right subtree * * @ return */ public int rightHeight() { if (right == null) { return 0; } return right.height(); } /** * Add node * * @ param node to subtree */ public void add(Node node) { if (node == null) { return; } //Judge whether the value of the incoming node is larger or smaller than the value of the root node of the current subtree. / / the added node is smaller than the value of the current node if (node. Value < this. Value) {/ / if the left node is empty if (this. Left = = null) {this. Left = node; / / if it is not empty} else {this. Left. Add (node);}} else {if (this. Right = = null) {this. Right = node;} else {this. Right. Add (node);}} / / query whether it is balanced / / rotate right if (leftheight() - rightheight() > = 2) {rightrotate();} //Left rotation if (leftheight() - rightheight() < = - 2) {leftrotate();} / * * * left rotation * / private void leftrotate() {node Newleft = new node (value) ; newleft.left = left; newleft.right = right.left; value = right.value; right = right.right; left = Newleft;} / * * rotate right * / private void rightRotate() {/ / create a new node whose value is equal to the current node's value Node newRight = new Node(value) ; / / set the right subtree of the new node to the right subtree of the current node newRight.right = right; / / set the left subtree of the new node to the right subtree of the left subtree of the current node newRight.left = left.right; / / change the value of the current node to the value of the left subtree of the current node value = left.value; / / set the left subtree of the current node to the left subtree of the current node The left subtree of the tree is left = left.left; / / set the right subtree of the current node as the new node right = newRight;}}
public class BinarySortTree { Node root; /** * Add node * * @ param node to binary sort tree */ public void add(Node node) { //If it is an empty tree, if (root = = null) {root = node;} else {root. Add (node);}}}
public class TestBinarySortTree { public static void main(String[] args) { // Int [] arr = New Int [] {8,9,6,7,5,4}; int [] arr = New Int [] {8,9,5,4,6,7}; / / create a binary sort tree BinarySortTree bst = new BinarySortTree(); / / add for (int i: ARR) {bst.add (new node (I));} / / check the height System.out.println(bst.root.height()); // System.out.println(bst.root.value); }}
Constructing double rotation of balanced binary tree
modify add method/** * Add node * * @ param node to subtree */public void add(Node node) { if (node == null) { return; } //Judge whether the value of the incoming node is larger or smaller than the value of the root node of the current subtree. / / the added node is smaller than the value of the current node if (node. Value < this. Value) {/ / if the left node is empty if (this. Left = = null) {this. Left = node; / / if it is not empty} else {this. Left. Add (node);}} else {if (this. Right = = null) {this. Right = node;} else {this. Right. Add (node);}} / / query whether it is balanced. / / perform right rotation if (leftheight() - rightheight() > = 2) {/ / double rotation if (left! = null & & left. Leftheight() < left. Rightheight()) {/ / rotate left.leftRotate() first ; / / rotate rightRotate(); / / single rotation} else {rightRotate();}} / / left rotation if (leftheight() - rightheight() < = - 2) {/ / double rotation if (right! = null & & right. Rightheight() < right. Leftheight()) {right. rightRotate(); leftrotate(); / / single rotation} else { leftRotate(); } }}
m-way search trees
Generally speaking, we all process data in memory, but if we want to operate the data set is very large, memory can not be processed, in this case, data processing needs to continuously transfer or transfer memory pages from hard disk and other storage devices.
The efficiency of reading and writing to external memory devices is not optimistic. In order to reduce the number of accesses to external memory devices, we need a new data structure to deal with this problem. For the tree we have learned before, a node can have multiple children, but it can only store one element. The binary tree has more restrictions, only two child nodes. When there are many elements, either the degree of the tree is very large (the node has the maximum number of subtrees), or the height of the tree is very large. If we want to find an element, we must access the external memory device many times, which forces us to break the restriction that each node can only store one element and introduce the concept of multi-channel search tree.
Multi way lookup tree: each node can have more than two children, and one node can store multiple elements. Because it is a lookup tree, there is a specific sorting relationship between all elements.
2-3 tree
The 2-3 tree is either empty or has the following properties:
- For 2-nodes, like ordinary BST nodes, there is a data field and two child node pointers. The two child nodes are either empty or a 2-3 tree. The data value of the current node should be greater than that of all nodes in the left subtree and less than that of all nodes in the right subtree.
- For a 3-node, there are two data fields a and b and three sub node pointers. All node data in the left sub tree should be less than a, all node data in the sub tree should be greater than a and less than b, and all node data in the right sub tree should be greater than b.
- All leaves are on the same layer
B-tree, also known as balanced multi fork search tree
Hashtable
Hash table (also known as hash table) is based on Key It directly accesses the data structure stored in memory. That is, it calculates a function about the Key value and maps the data to be queried to a location in the table to access the records, which speeds up the search speed. This mapping function is called hash function, and the array storing records is called Hash list.
Design of hash function
-
direct addressing
-
Digital analysis
-
Square middle method
-
Residual method
-
Random number method
public class StuInfo { private int age; private int count; public int getAge() { return age; } public void setAge(int age) { this.age = age; } public int getCount() { return count; } public void setCount(int count) { this.count = count; } /** * Hash function */ @Override public int hashCode() { return age; } public StuInfo(int age, int count) { this.age = age; this.count = count; } public StuInfo(int age) { super(); this.age = age; } @Override public String toString() { return "StuInfo [age=" + age + ", count=" + count + "]"; }}
public class HashTable { private StuInfo[] data = new StuInfo[100]; /** * Add element to hash * @ param stuInfo */ public void put(StuInfo stuInfo) { //Call the hash function to get the storage location int index = stuInfo.hashCode(); / / add the element data [index] = stuInfo;} public stuInfo get (stuInfo stuInfo) {return data [stuInfo. Hashcode()];} @ override public string tostring() {return "hashtable [data =" + arrays. ToString (data) + "];}}
public class TestHashTable { public static void main(String[] args) { StuInfo s1 = new StuInfo(16, 3); StuInfo s2 = new StuInfo(17, 11); StuInfo s3 = new StuInfo(18, 23); StuInfo s4 = new StuInfo(19, 24); StuInfo s5 = new StuInfo(20, 9); HashTable ht = new HashTable(); ht.put(s1); ht.put(s2); ht.put(s3); ht.put(s4); ht.put(s5); System.out.println(ht); //Target data stuInfo target = new stuInfo (18); StuInfo info = ht.get(target); System.out.println(info); }}
Solution to hash conflict
No matter how ingenious the hash function is designed, there will always be special key s that cause hash conflicts, especially for dynamic lookup tables.
hash function conflict resolution methods include the following common methods
- Open customization method
- Linear exploration method
- Secondary detection method
- Re hashing method
- Chain address method
chart
Graph is a data structure composed of Vertex set and relationship set between vertices. The relationship between vertices becomes an Edge. A graph G is marked as g = (V,E), V is the finite set of vertices Vi, n is the number of fixed points: E is the finite set of edges
Undirected graph
Directed graph
Complete graph
Weighted graph
adjacent vertex
/** * Vertex class */ public class Vertex { private String value; public String getValue() { return value; } public void setValue(String value) { this.value = value; } public Vertex(String value) { super(); this.value = value; } @Override public String toString() { return value; } }
/** * chart */ public class Graph { private Vertex[] vertex; public int[][] adjMat; //Subscript of current traversal private int currentIndex; public Graph(int size) { vertex = new Vertex[size]; adjMat = new int[size][size]; } /** * Add a vertex to the graph * * @param v */ public void addVertex(Vertex v) { vertex[currentSize++] = v; } public void addEdge(String v1, String v2) { // Find the subscript of the two vertices int index1 = 0; for (int i = 0; i < vertex.length; i++) { if (vertex[i].getValue().equals(v1)) { index1 = i; break; } } int index2 = 0; for (int i = 0; i < vertex.length; i++) { if (vertex[i].getValue().equals(v2)) { index2 = i; break; } } adjMat[index1][index2] = 1; adjMat[index2][index1] = 1; } }
public class TestGraph { public static void main(String[] args) { Vertex v1 = new Vertex("A"); Vertex v2 = new Vertex("B"); Vertex v3 = new Vertex("C"); Vertex v4 = new Vertex("D"); Vertex v5 = new Vertex("E"); Graph g = new Graph(5); g.addVertex(v1); g.addVertex(v2); g.addVertex(v3); g.addVertex(v4); g.addVertex(v5); //Add edge g.addEdge("A", "C"); g.addEdge("B", "C"); g.addEdge("A", "B"); g.addEdge("B", "D"); g.addEdge("B", "E"); for(int[] a:g.adjMat) { System.out.println(Arrays.toString(a)); } } }
Depth first search algorithm
Breadth First Search
/** * Vertex class */ public class Vertex { private String value; public boolean visited; public String getValue() { return value; } public void setValue(String value) { this.value = value; } public Vertex(String value) { super(); this.value = value; } @Override public String toString() { return value; } }
/** * chart */ public class Graph { private Vertex[] vertex; private int currentSize; public int[][] adjMat; private MyStack stack = new MyStack(); //Subscript of current traversal private int currentIndex; public Graph(int size) { vertex = new Vertex[size]; adjMat = new int[size][size]; } /** * Add a vertex to the graph * * @param v */ public void addVertex(Vertex v) { vertex[currentSize++] = v; } public void addEdge(String v1, String v2) { // Find the subscript of the two vertices int index1 = 0; for (int i = 0; i < vertex.length; i++) { if (vertex[i].getValue().equals(v1)) { index1 = i; break; } } int index2 = 0; for (int i = 0; i < vertex.length; i++) { if (vertex[i].getValue().equals(v2)) { index2 = i; break; } } adjMat[index1][index2] = 1; adjMat[index2][index1] = 1; } /** * Depth first search algorithm traversal graph */ public void dfs() { //Mark the 0th vertex as accessed vertex[0].visited = true; //Subscript the 0 th vertex. stack.push(0); //Print vertex values System.out.println(vertex[0].getValue()); //ergodic out: while (!stack.isEmpty()) { for (int i = currentIndex + 1; i < vertex.length; i++) { //If it is connected to the next traversal element if (adjMat[currentIndex][i] == 1 && vertex[i].visited == false) { //Push the next element onto the stack stack.push(i); vertex[i].visited = true; System.out.println(vertex[i].getValue()); continue out; } } //Pop up stack top element stack.pop(); //Modify the current position to the position of the top element of the stack if (!stack.isEmpty()) { currentIndex = stack.peek(); } } } }
public class TestGraph { public static void main(String[] args) { Vertex v1 = new Vertex("A"); Vertex v2 = new Vertex("B"); Vertex v3 = new Vertex("C"); Vertex v4 = new Vertex("D"); Vertex v5 = new Vertex("E"); Graph g = new Graph(5); g.addVertex(v1); g.addVertex(v2); g.addVertex(v3); g.addVertex(v4); g.addVertex(v5); //Add edge g.addEdge("A", "C"); g.addEdge("B", "C"); g.addEdge("A", "B"); g.addEdge("B", "D"); g.addEdge("B", "E"); for(int[] a:g.adjMat) { System.out.println(Arrays.toString(a)); } //Depth first traversal g.dfs(); } }