Showing posts with label Re-view. Show all posts
Showing posts with label Re-view. Show all posts

[Re-View]Hash Table (Basics)

Hash table Basics



Intro

The concept, usage and implementations of Hash table are always used in Software Engineer interviews. From the interview guidance of Google, there is an requirement of hash table. It is said "Hashtables: Arguably the single most important data structure known to mankind." There is indeed a bunch of knowledge and techniques for hashtables (hash function, collision, etc.), but from the interview perspective, it is not possible to test the thorough and complete skills of hashtables in a short interview. Take this advantage, in this post, I'd like to learn the basics of hash tables, and try to implement sample code.

What is Hash Table?

It is a very common but often occurred question in IT interviews. I generalize the concept in my own words: " Hash table, is a data structure, which stores key-value pairs, the access of value by key can be O(1) time, a hash function is used to map the key to the index of the value."

You can find many many definitions of hash table, generally speaking, you can imagine hash table is an array, originally we access an element in array by using index, e.g. A[1], A[2]. However in hash table, we access element by the key,  e.g. A["Monday"], D["Marry"].  The great advantage of it is the speed to look up an element (O(1) time). 

How does Hash table works

Firstly, hash tables can be implemented based on many data structures, e.g. Linked list, array and linked list, binary search tree, etc. The idea is to store the <key, value> pair and build a way to access it. For better understanding, just consider an array, we put the <key, value> in a specific order. The way to locate the <key, value> using the key is called hashing. We can consider a hash function takes the key as the input, and output the location of the <key, value> in the array. A simple hash function is to used "mod" operation.  Use the "key mod array size" to get the hash, the index of the desired value. 


An example

Let's see a simple example.
We have a storage of  size 5:
idx      key       value
0         -1           0
1         -1           0
2         -1           0
3         -1           0
4         -1           0
key=-1 means the slot is empty.
The hash function is   hash(key) = key % 5;
First we insert <12, 12>  (first is key, second is value)
Compute the hash(12) = 2;
Store the <key, value> into the storage of idx 2.
idx      key       value
0         -1           0
1         -1           0
2         12          12
3         -1           0
4         -1           0
Next we insert <29,29>, hash(29)=4;
idx      key       value
0         -1           0
1         -1           0
2         12          12
3         -1           0
4         29          29
Then we insert <27,27>, where the hash code is 2. When we check the location 2, it is already in use. 
It is called a collision, where different key are mapped into same hash code. To deal with the collision, there are many methods, such as, chaining (use a linked list for each location), and rehashing (second function is used to map to another location). Usually we need to know at least these two kinds of methods.
Here we use the rehashing.  

The rehashing function is:  rehash(key) = (key+1)%5;
So, continue the above step, rehash(2) = 3; location 3 is empty, then store the <27,27> to location 3.
idx      key       value
0         -1           0
1         -1           0
2         12          12
3         27          27
4         29          29

If we further insert <32,32>, hash(32) = 2; location 2 is in use, rehash(2) = 3, location 3 is also in use,
Then rehash again, rehash(3) = 4, no available, rehash(4) = 0, OK! Store <32, 32 > in 0th slot.

idx      key       value
0         32          32
1         -1           0
2         12          12
3         27          27
4         29          29

That is the basic way of insert operation for a hash table.

To retrieve the value, e.g. we want to find the value of key <27, ?>, hash(27) = 2, check the key stored in location 2 , which is 12 !=27, then rehashing is need, rehash(2) = 3,  the key is 27, then return the value 27.

A simple implementation (in C++)

#include <iostream>


using namespace std;

const int sz = 5;

struct data{
 int id;
 int val;
};

class Hashtable{
 data dt[sz];
 int numel;
public:
 Hashtable();
 int hash(int &id);
 int rehash(int &id);
 int insert(data &d);
 int remove(data &d);
 int retrieve(int &id); 
 void output();
};


Hashtable::Hashtable(){
 for (int i=0;i<sz;i++){
   dt[i].id = -1;
dt[i].val = 0;
 }
 numel = 0;
}

int Hashtable::hash(int &id){
 return id%sz;
}

int Hashtable::rehash(int &id){
 return (id+1)%sz;
}

int Hashtable::insert(data &d){
 if (numel<sz){
   int hashid = hash(d.id);
if (hashid>=0 && hashid < sz){
 if (dt[hashid].id==-1 || dt[hashid].id==-2){
   dt[hashid].id = d.id;
   dt[hashid].val = d.val;
           numel++;
   return 0;
 }else{
   cout << "collision! rehashing..." <<endl;
   int i=0;
   while (i<sz){
     hashid = rehash(hashid);
 if (dt[hashid].id==-1 || dt[hashid].id==-2){
   dt[hashid].id = d.id;
   dt[hashid].val = d.val;
   numel++;
   return 0;
     }
 if (i==sz){return -1;}
 i++;
}
 }
}
 }else{return -1;}
}

int Hashtable::remove(data &d){
 int hashid = hash(d.id);
if (hashid>=0 && hashid < sz){
 if (dt[hashid].id==d.id){
   dt[hashid].id = -2;
   dt[hashid].val = 0;
   numel--;
   return 0;
 }else{
   int i=0;
   while (i<sz){
     hashid = rehash(hashid);
 if (dt[hashid].id==d.id){
   dt[hashid].id = -2;
   dt[hashid].val = 0;
   numel--;
   return 0;
     }
 if (i==sz){return -1;}
 i++;
}
 }
}
}

int Hashtable::retrieve(int &id){
 int hashid = hash(id);
 if (hashid>=0 && hashid < sz){
   if (dt[hashid].id==id){
 return dt[hashid].val;
}else{
  int i=0;
   while (i<sz){
     hashid = rehash(hashid);
 if (dt[hashid].id==id){
   return dt[hashid].val;
 }
 if (i==sz){return 0;}
 i++;
}
}
 }
}

void Hashtable::output(){
 cout << "idx  id  val" << endl;
 for (int i=0;i<sz;i++){
   cout << i << "    " << dt[i].id << "    " << dt[i].val << endl; 
 }
}


int main(){
 Hashtable hashtable;
 data d;
 d.id = 27;
 d.val = 27;
 hashtable.insert(d);
 hashtable.output();
 
 
 d.id = 99;
 d.val = 99;
 hashtable.insert(d);
 hashtable.output();
 
 d.id = 32;
 d.val = 32;
 hashtable.insert(d);
 hashtable.output();
 
 d.id = 77;
 d.val = 77;
 hashtable.insert(d);
 hashtable.output();
 
 //retrieve data
 int id = 77;
 int val = hashtable.retrieve(id);
 cout << endl;
 cout << "Retrieving ... " << endl;
 cout << "hashtable[" << id<< "]=" << val << endl;
 cout << endl;
 
 
 //delete element
 d.id = 32;
 d.val = 32;
 hashtable.remove(d);
 hashtable.output();
 
 d.id = 77;
 d.val = 77;
 hashtable.remove(d);
 hashtable.output();
 
     
 return 0;
}
 


[Re-view] Recursive: Array Permutations



Intro

For the recursive function, it is very easy for most of us to write code for the fibonacci sequence. ( f(n)=f(n-1)+f(n-2) ). It seems we already got the idea of the recursion. What if you are asked to write the code for "8 queens problem" (actually this is also not hard at all) on a piece of paper? Some of you might feel  difficulty to rapidly and accurately do so. If you feel comfortable to write code for many recursive problem, you can definitely jump this post. But if you are easily confused facing slight complex recursive problems like me, maybe you wanna continue reading this post. From my experience, the 1st thing is to ask yourself, what are you thinking or what came out of you mind once you see a recursive problem? Recursion? Function argument list? Stop condition? for loop? Some lines of code?

Well, I'm neither good at remembering things, nor understanding things quickly. When I face the recursive problems, it's always a big mess! I just know this can be solved by recursion (and usually also DP, which is much harder), then I don't know what to do... So sad...

There is a saying that "Practice makes perfect" ! And "If you review the past, you will see new things!" In this post I will discuss the problem "Array permutation". I'll focus on the recursive procedure and present the way I remember the algorithm. Hopefully this will help you a little, but different people have different ways learning the same thing, try to find your own way, that is important.



Problem

Given an array of elements, return all the permutations.
e.g. Input: (1,2,3)
Return:  (1,2,3), (1,3,2), (2,1,3), (2,3,1), (3,1,2), and (3,2,1). 

Idea

First, we must make sure the problem can be solved using recursion. 
Usually, the problem which can be divided into sub problems is highly considered to be solvable using recursion.e.g. F(n)=F(n-1)+F(n-2). However, in this problem, it is not easy to see the sub problem. It may not work considering the length of the array, but it seems ok to consider each position. From the first element to the last... Every time I'm thinking of this, I have no way to go... 
Then I will remind myself about the recursion.  If the "function" e.g. f(n)=f(n-1)... cannot work, then I usually consider the following points:
1. Can I draw a Tree?
2. What are the stop/return conditions?
3. Does it need the backtracking?
4. Try to remember some standard code:
              func(){
                 if meet stop condition, return
                 else
                    for (i=1:n){
                        do something
                        func(next);
                        may need backtracking;
                    }
               }
      Despite this is not the master key solving the recursion, but it helps a lot when you have no idea at all.


If I can draw a tree, the problem is more straightforward and it related to the tree traversal problem, if you are familiar with that code, it would helps you a lot. If not, it is also easier to design the recursive function.

Stop/return condition is important. You have to think when your program will stop, when will it output the result. It is also the key to the recursion.

Backtracking is another issue when you do the "search", sometimes it is not needed, but sometimes you have to change back the status so that the search is not missing some branches. e.g., usually when there is loop in your recursion, be cautious!

For this problem, if you can draw a tree like this,  you are almost getting there! 

NewPermutation

Then think about to construct the recursive function in your mind, see the tree and consider every node is a new function call:
Argument list: what we have to know in each recursion? The array and the length, the current position (a,n,k)
Stop condition: when all the positions are searched, print the output (if k==n)
Search rule:  swap current position with all the following positions (for i= k: n, swap)
Recursive:    fix current position, go to next position (perm(a, k+1,n))
Backtracking: needed! because there is a for loop, we swap the array before perm, so we swap back after.

Given these, writing code seems not hard then:

perm(int* A, int k, int n){
  if (k==n) {print(A); // print out the array, you can define by yourself}
  else{
    for (int i=k;i<n;i++){
      swap(A[i],A[k]); // swap the two values, you can define by yourself
      perm(A,k+1,n);
      swap(A[i],A[k]);
    }
  }
}


Some suggestions:


Please read the code carefully and according to the tree figure, you will find your own way understand that。
Please try to remember some classic recursive problems, don't have to remember every line of code, but the key lines or the structures of the function.
When you face a new problem, try to think the sub-problem, or the easy case (e.g. the number is 0 or 1).


I'll give more examples in the later posts.


(finished)








[Re-view] Common Sorting Algorithms: Concepts and Implementations

Common Sorting Algorithms: Concepts and Implementations  


Introduction


Understanding the basic concepts of the popular sorting algorithms, can not only help you better understand the data structure and algorithm from a different perspective, but also helps you make the computational complexity clearer in your mind. Besides, sorting related questions, are also hot questions in your software engineering job interview.

Many books, courses, and websites are providing massive materials of sorting algorithms.  From my own experiences, among the long and tedious sources, http://www.sorting-algorithms.com/, and https://en.wikipedia.org/wiki/Sorting_algorithm are two good places you can learn the sorting algorithm intuitively, because there are animations shown in the website. If you have already familiar or have the basic concept of the sorting algorithms, it would help you easily memorize the details of specific algorithm.

In this blog, I'd like to review the common popular sorting algorithms, with the basic concepts, and tries to explain each one intuitively. Also the C++ implementation is the core content and are provided detailed with comments. This blog is more suitable for who have already implemented some of the sorting algorithms (at least you may write the selection sorting or bubble sorting in 1 or 2 minutes), but I will try to explain more for the novices.


1. What algorithms are covered ?


  1.     Bubble sort  
  2.     Selection sort
  3.     Inset sort
  4.     Merge sort
  5.     Quick sort
  6.     Heap sort
  7.     Bucket sort

2. Computational Complexity   

  1.     Bubble sort                       O(n^2 )
  2.     Selection sort                    O(n^2)
  3.     Inset sort                           O(n^2)
  4.     Merge sort                        O(nlogn)
  5.     Quick sort                         O(nlogn)
  6.     Heap sort                          O(nlogn)
  7.     Bucket sort                       O(n+k)
    How to know these in a fast way?  Just memorize them!  My experience is that 
  • If there are 2 loops in the code, it is O(n^2)
  • If the algorithm is easily implemented, it is O(n^2)" 
  • Otherwise it is O(nlogn), expect the bucket sort.

3. Concepts and Implementations

The sorting problem is quite straightforward----sort the data array (ascending order). We will not go into the detail that what kind of data structure or data type are used, and not interested in the comparison function.

Here we define the general case:
Input: 
    int n; //array length
    int* A[n];  // unsorted int array
Output:
   int* A;      // sorted array (ascending order)

Function:
  swap(int a, int b) // swap the value of a and b
  
void swap(int &a,int &b){
 int tmp;
 tmp = a;
 a = b;
 b = tmp;
}

In the following, I'll show the key concept and the way how I  remember these sorting algorithms.
NOTE that there may have different forms for  one sorting algorithm, here just shows one of them.
NOTE that to better understand the following, I personally suggest read the code directly along with the explanations.



Bubble sort

-----------------------------------------------------------------------------------
Concept: 
Scan from start to end, compare every two elements, swap the max to the end.
Scan from start to end-1, compare every two elements, swap the max to the end-1.
Scan from start to end-2, compare every two elements, swap the max to the end-2.
...
Scan from start to start, end.

Key Point:
if A[j]>A[j+1], swap(A[j], A[j+1]);

How to Memorize:
Compare each pair and bubble the max value out and move to the last.

Code:
//Bubble Sort
void bubbleSort(int *A, int n){
  for (int i=n-1;i>0;i--){
    for (int j=1;j<=i;j++){
      if (A[j]<A[j-1]){
        swap(A[j],A[j-1])       
      }
    }
  }
}





Selection sort


-----------------------------------------------------------------------------------
Concept:
From 1st to last, find the min value,  store to the 1st position.
From 2nd to last, find the min value, store to the 2nd position.
From 3rd to last, find the min value, store to the 3rd position.
...
From last-1 to last, find the smaller one, store to the last-1 position. End.

Key Point:
k=i;  // store the current start position
if (A[j]<A[k]) {k=j;} // store the index of min value

How to Memorize:
Select the min value and store to the front.

Code:
//Selection Sort
void selectSort(int *A, int n){
  for (int i=0;i<n-1;i++){
    int k=i; // k can be viewed as the index of min value
    for (int j=i+1;j<n;j++){ // find the min value
      if (A[j]<A[k]){k=j;}
    }
    swap(A[i],A[k]);  // store the min value to the start
  }
}






Inset sort


-----------------------------------------------------------------------------------
Concept:
For each element A[i], the array A[0..i-1] is already sorted. Scan A[0..i-1], find the correct place and insert A[i].

Key Point:
Find the correct place and insert the A[i] in sorted A[0..i-1].
Consider A[0..i]:   [1,3,4,5,8,2],
So, A[i]=2.
Store it to a variable: tmp = A[i];
What we need to do now?
[1,3,4,5,8,2] ---->  [1,2,3,4,5,8]
How to do this?
Keep moving each element to its right (A[j]=A[j-1]), until the next element is less than  A[i].

How to Memorize:
Insert every element to its previous sorted array.

Code:
//Insert Sort
void insertSort(int *A, int n){
  for (int i=0;i<n;i++){
    int tmp = A[i];
    int j=i;
    while (j>0 && tmp<A[j-1]){
        A[j]=A[j-1];
        j--;
    }
    A[j]=tmp;   
  }
}






Merge sort


-----------------------------------------------------------------------------------
Concept:
Here I interpret merge sort using the recursion. So hopefully you have the basic idea what recursion is.
The idea is mainly considering the array into smaller subsets,  merge the smallest subsets to smaller subset, merge smaller subsets to small subset ... until merge subset to the whole array. Merging process itself handles the sorting.

This figure (from wikipedia) shows the exact process of merge sort. Please go through the whole tree at the same time thinking it as a recursive problem, this will greatly help you understand the implementation of this algorithm.

Key Point:
Merge sort consist two parts:
(1) Recursion Part.
(2) Merge Part.

Recursive part, handles divided the current set to two parts, just like the concept of divide-and-conquer: Find the middle, divide into left and right subset and continue dividing in each subset. Recursion also keeps the two subset sorted for the merging.

Merge Part, is very very important for this algorithm, which merges two array to make a new sorted array.
How to do it ? Let's take a example.
Assume: A1=[1,5,7,8] and A2=[2,6,9,10,11,12,13]
What we need ?  A new sorted array A = [1,2,5,6,7,8,9,10,11,12,13]
OK, now at least we need a new array
A of length A1+A2, say,  A[ , , , , , , , ,].
How to put element in A and considering the order?
Set 3 pointers i,j,k, for A1, A2, and target array A.
A1=[1,5,7,8]
        i
A2=[2,6,9,10,11,12,13]
        j
A =[ , , , , , , , ,].
       k
From above one can clearly see, the 1st element in A (A[k]), should be min(A1[i],A2[j]), it is A1[i] = 1. So A1[i] is already in A, then we go to the next element in A1 using i++.  And the 1st element in A is filled, we have to go to the next one, so k++.
A1=[1,5,7,8]
            i
A2=[2,6,9,10,11,12,13]
        j
A =[1, , , , , , , ,].
          k
Next,  similarly compare A[i] and A[j],  get the smaller one and fill into the array A, and set the pointers properly.
A1=[1,5,7,8]
            i
A2=[2,6,9,10,11,12,13]
            j
A =[1,2, , , , , , ,].
             k    
In such a way, the loop goes until the end of A1. At this time, the merge is NOT finished, we have to combine the rest elements of A2 into A.
Finally,  A = [1,2,5,6,7,8,9,10,11,12,13].


How to Memorize:
(1) Recursion Part: divide from the middle
(2) Merge Part:  merge two sorted array into one sorted array


Code:
//Merge Sort
void mergeSort(int *A, int st, int ed){
  if (st>=ed) {return;}
  int m = st+(ed-st)/2;
  mergeSort(A,st,m);
  mergeSort(A,m+1,ed);
  
  int *tmp = new int[ed-st];
  int k=0; 
  int i=st;
  int j=m+1;
  
  while (i<m+1 && j<=ed){   
    if (A[i]<A[j]){
       tmp[k++]=A[i++];
    }else{
 tmp[k++]=A[j++];    
    }
  }
  while (i<m+1){tmp[k++]=A[i++];}
  while (j<=ed){tmp[k++]=A[j++];}
  
  for (int ii=0;ii<k;ii++){cout <<tmp[ii] <<" ";}
  cout << endl;
  
  for (int ii=st; ii<=ed;ii++){ A[ii] = tmp[ii-st];}
  delete [] tmp; 
 
}






Quick sort


-----------------------------------------------------------------------------------
Concept:
This is also a Divide and Conquer algorithm. The idea is:  for an element pivot in the array, place the elements less than pivot to its left, and elements greater than pivot to its right. Do this same procedure to the two subsets (left and right), until all the elements are sorted.

Key Point:
Quick sort mainly consisted two parts:
(1) Recursive part: recursively apply the for the subsets.
(2) Reorder the set, where elements < pivot value are placed to its left, and vice versa.
     This is the important part of the algorithm:
     Consider the array
     A=[8,3,5,6,4,1,9]
     Here we choose the middle element as the pivot (also can select the 1st one or randomly select)
     What we want to do ?
    A[1,3,5,4,6,8,9],  then sort[1,3,5,4,6] and [8,9] recursively.

     First, put pivot to the front (swap(A[0],A[pivot])):
     A=[6,3,5,8,4,1,9]
    Then set two pointers i and p, start from the 2nd element. p points to the first element which is bigger than pivot. 
     A=[6,3,5,8,4,1,9]
               i        
              p
    Compare A[i] with A[0], if A[i] < A[0], swap A[i] and A[p], goto next.
     A=[6,3,5,8,4,1,9]
                  i        
                 p
     and
     A=[6,3,5,8,4,1,9]
                     i        
                    p
     here A[i]>A[0], no swap, i++
     A=[6,3,5,8,4,1,9]
                        i        
                    p
     4<6, swap A[i] and A[p], because A[p] was found larger than A[0]
     A=[6,3,5,4,8,1,9]
                           i        
                       p
     Still have to swap:
     A=[6,3,5,4,1,8,9]
                              i        
                          p
     No swap, i goes to the end, and now p is the place where 0..p-1 < pivot, and p..n > pivot.
     Last step is to swap A[0] and A[p-1]:
    A[1,3,5,4,6,8,9]

How to Memorize:
(1) Recursion (divide-and-conquer)
(2) Select a Pivot
(3) Aim: reorder elements<pivot to the left and elements>pivot to the right
(4) Set pivot to front
(5) Set two pinter


Code:
//Quick Sort
void quickSort(int *A, int st, int ed){
 if(st>=ed){return;}
 int pivot = st+(ed-st)/2;
 swap(A[st],A[pivot]);
 int pos = st+1;
 for (int i=st+1;i<ed;i++){
   if (A[i]<A[st]){
     swap(A[i],A[pos]);
     pos++;
   }
 }
 swap(A[pos-1],A[st]);
 quickSort(A,st,pos-1);
 quickSort(A,pos,ed);
 
}






Heap sort


-----------------------------------------------------------------------------------
Concept:
Heap sort is based on the data structure heap, which is a tree structure with a nice ordering property, can be used for sorting.  The heap sort algorithm consists of two parts:
(1) Construct the heap
(2) Get the root node each time, update the heap, until all the node are removed.

First let's see what is heap (in my own word):
A heap, briefly speaking, is a tree structure, where the value of each parent node is greater/smaller than its children. Practically in the heap sort, we use the specific kind of heap----binary heap.

Binary heap,  is a complete binary tree, also keeps the property that each root value is greater or smaller than its left and right children. Thus, the root of the tree is the biggest (called max heap) or the smallest (called min heap) element in the tree.

Caution!!!  A Heap is NOT a binary search tree(BST)! A BST can apply in-order traversal to get the sorted  array, heap CANNOT guarantee the ordering within same level, so it does not have a specific requirement of the order for the left and right children. e.g. see the figure below(from wikipedia)
A heap structure: 
A binary search tree structure: 




  • How to construct the heap?
          Consider a unsorted array, we want to construct a heap. The intuitive way is to obtain every node and add to the tree structure(TreeNode* blablabla...), but a simpler way is just use the array itself, to represent the tree and modify the value to construct the heap.

       Tree  (Array  representation):
            Root node: A[0].
            Left child   of A[i]:  2*i+1
            Right child of A[i]:  2*i+2
            Parent of A[i]:        (i-1)/2

      Construct a heap:
           An operation downshift is used here.
           The idea of downshift is to adjust the current node to its proper position in its downside direction.
           Given a node, compare the value to the bigger one of its left and right children, is the value is smaller than the bigger children, then swap them. And keep checking the node (here in the new position after swapping), until it is no less than its children.
            To construct the heap, from the end of the array, we downshift every node to the first in the array.
         
  • How to get the sorted array according to the heap?
         Given a max heap, the value of root node is the biggest in the heap, each time remove the top node and store to the array. But it's not enough! We have to keep the heap, so there needs a update of the remaining nodes.  An efficient way is just swap the root node and the last element of the tree, remove the last node (just let the length of the array -1), downshift the new root node, a heap is updated.



Key Point:
(1) How to construct the heap?
      Use array to represent the tree structure.
      Recursively downshift every node.
(2) How to get the sorted array according to the heap?
      Each time remove the root of the heap, swap the last node to the root and downshift it.
      Until all the nodes are removed.

How to Memorize:
This algorithm is very particular and requires the skill of heap operations (construct, downshift, update, etc.).
In my opinion, first you get to know the data structure heap, then the heap sort suddenly becomes a piece of cake!

Code:
//Heap Sort
void downshift(int* A, int n, int parent){
  if (parent<0 ){return;}
  int left = parent*2+1;
  int right = parent*2+2;
  int mxch;
  if (left>=n) {return;}
  if (right>=n) {mxch=left;}
  else{mxch = A[left]>=A[right]?left:right;}
  if (A[parent]<A[mxch]){
    swap(A[parent],A[mxch]);
    downshift(A, n,mxch);
  } 
}

void constructHeap(int *A, int n){
  int parent=(n-2)/2;
  for ( ;parent>=0;parent--){ 
    downshift(A, n, parent);
  } 
}

void heapSort(int *A, int n){
constructHeap(A,n);
int i=n-1;
int *B=new int[n];
while (i>=0){
  B[n-i-1]=A[0]; //get the biggest in the heap
  swap(A[0],A[i]);
  downshift(A,i,0);
  i--;
}
A=B;
}







Bucket sort (coming soon)


-----------------------------------------------------------------------------------
Concept:
Key Point:
How to Memorize:
Code:
aaa