Tuesday, March 31, 2020

Review Materi

Oke sampailah materi di bagian review materi sebelum UTS, materi UTS nanti akan membahas Linked list Single maupun Doubly;Stack, dan queue; hashing; Tree/Binary Tree; Binary Search Tree.

1. Single Linked List
saya hanya membahas dari segi pengimplementasi saja, okee langsung saja

pertama kita buat Struct data untuk menyimpan data, di Single kita hanya menggunakan next sebagai petunjuk dan head sebagai kepala dan tail sebagai data terakhir.

struct data{
int angka;
char name[100];
data *next;
}*head,*tail ;

Setelah itu membuat memory allocate agar komputer menyediakan memory yang pas dan tidak kurang,  dan saat di malloc sebelum nya harus di type casting.

data* newData(char name[],int angka){
data* curr =(data*)malloc(sizeof(data));
curr->angka=angka;
strcpy(curr->name,name);
curr->next=NULL;
return curr;
}

sekarang kita sudah memesan memori ke komputer kita, setelah itu kita buat push Depan,

void pushHead(data *curr){
if(head==NULL){
head=tail=curr;
}else{
curr->next=head;
head=curr;
}
}
penjelasan code ya tersebut adalah kondisi awal data tersebut sama dengan NULL maka head=tail=curr dalam satu tempat, kondisi else ya adalah kita ingin memasukkan data dan menyambungkan data tersebut maka kita membutuhkan curr->next = head, current ke next diubah mejadi head, dan head diubah ke curr.

Setelah itu kita buat push Belakang,

void pushTail(data *curr){
if(head==NULL){
head=tail=curr;
}else{
tail->next=curr;
tail=curr;
}
}

kondisi awal sama seperti push Depan, dan kondisi else ya tail ke next diubah menjadi curr dan tail menjadi curr.

oke lanjut ke Pop/delete

pertama delete Head/depan.
void popHead(){
if(head==tail){
head=tail=NULL;
free(head);
}else{
data *temp = head;
head=head->next;
temp->next=NULL;
free(temp);
                temp = NULL;
}
}

kedua delete Belakang/tail
void popTail(){
if(head==tail){
head=tail=NULL;
free(head);
}else{
data *temp=head;
while(temp->next!=tail){
temp=temp->next;
}
free(tail);
tail=temp;
tail->next=NULL;
}
}

dalam implementasikan harus membuat function untuk print sebagai berikut:
void printAll(){
data *temp=head;
while(temp!=NULL){
printf("%d %s\n",temp->angka,temp->name);
temp=temp->next;
}
}

2. Double Linked List
di doubly sedikit berbeda dengan single karena di double ini memiliki tambahan petunjuk prev. oke langsung pengimplementasi saja. sama aja ya harus membuat struct dan malloc (memory alloce), saya di sini langsung membahas ke push dan pop aja.

struct data{
int angka;
char name[101];
data *next, *prev;
}*head,*tail;

data *newData(char name[],int angka){
data *curr =(data*)malloc(sizeof(data));
curr -> angka=angka;
strcpy(curr->name,name);
curr -> prev = curr -> next = NULL;
return curr;
}

push Depan
void pushHead(data *curr)
{
if(head==NULL)
{
head = tail = curr;
}
else
{
head -> prev=curr;
curr -> next=head;
head = curr;
}
}

Push Belakang
void pushTail(data *curr)
{
if(head==NULL)
{
head=tail=curr;
}
else
{
tail -> next=curr;
curr-> prev= tail;
tail = curr;
}
}

Pop Depan
void popHead()
{
if(head==tail)
{
head=tail=NULL;
free(head);
}
else
{
data*temp=head;
head=head->next;
temp->next=NULL;
free(temp);
}
}

Pop Belakang
void popTail()
{

if(head==tail)
{
head=tail=NULL;
free(tail);
}
else
{
data*temp=tail;
tail=tail->prev;
tail->next=NULL;
free(temp);
}
}

Pop Semua nya
void popAll()
{
while(head!=NULL)
{
popHead();
}
}

print data
void printAll()
{
data *temp=head;
while(temp != NULL)
{
printf("%s %d\n",temp->name, temp->angka);
temp = temp->next;
}
}

3. Stack & Queue
a. Stack ini sama aja dengan linked list, ini sistem ya LIFO
sistem ya Last in First Out, maka dari menggunakan push Tail dan pop Tail
b. Queue sistem ya FIFO ( First In First Out), maka menggunakan Push Head dan Pop Head

4. Hashing
materi ini langsung ke implementasi saja
a. hashing secara linear Probling
const int tableSize = 27;
char hashTable[tableSize][100];
int generateKey(char *name)//SmallCase{
int result = name[0] - 'a';
return result;
}

void insert(char *name){
int idx = generateKey(name);
strcpy(hashTable[idx],name);
}

void print(){
for(int i=0;i<tableSize;i++){
printf("[%-2d] : %s\n",i, hashTable[i]);
}
}

b. hashing secara Chaining
struct tnode{
char name[100];
int key;
struct tnode *next;
};

struct hashPool{
struct tnode *head;
struct tnode *tail;
};

const int tableSize = 97;
struct hashPool hashTable[tableSize];

int generateKey(const char *name){
int result = 0;
int len=strlen(name);
for(int i=0;i<len;i++){
result += name[i];
}
return result % tableSize;
}

struct tnode *newNode(const char *name){
struct tnode *curr =(struct tnode*)malloc(sizeof(struct tnode));
strcpy(curr->name,name);
curr->key=generateKey(name);
curr->next=NULL;
return curr;
}

void insert(struct tnode *node){
if(hashTable[node->key].head==NULL){
hashTable[node->key].head=hashTable[node->key].tail=node;
}
else{
hashTable[node->key].tail->next=node;
hashTable[node->key].tail=node;
}
}

void print(){
for(int i=0;i<tableSize;i++){
printf("[%2d] : ",i);
tnode *curr = hashTable[i].head;
while(curr){
printf("%-10s ->",curr->name);
curr=curr->next;
}
printf("NULL\n");
}
}

5. Tre/Binary Tree
struct data{
int value;
data *left;
data *right;
};

struct data *newData(int value){
data *curr=(data*)malloc(sizeof(data));
curr->value=value;
curr->left=NULL;
curr->right=NULL;
return curr;
}

void inOrder(data *root){
         if(root){
inOrder(root->left);
printf("%d ",root->value);
inOrder(root->right);
}
}
void preOrder(data *root){
if(root){
printf("%d ",root->value);
preOrder(root->left);
preOrder(root->right);
}
}

void postOrder(data *root){
if(root){
postOrder(root->left);
postOrder(root->right);
printf("%d ", root->value);
}
}

struct data *freeAll(data *root){
if(root){
freeAll(root->left);
freeAll(root->right);
free(root);
root=NULL;
}
return root;
}

6. Binary Search Tree
struct data{
    int umur;
    struct data *left;
    struct data *right;
};

struct data* newData(int umur){
    struct data* newNode = (struct data*)malloc(sizeof(struct data));
    newNode->umur = umur;
    newNode->left = NULL;
    newNode->right = NULL;
    return newNode;
}

struct data* insertion(struct data* root,int umur){
    struct data* temp = newData(umur);
    if(root == NULL) root = temp;
    else if(umur  > root->umur) root->right = insertion(root->right,umur);
    else if(umur < root->umur) root->left = insertion(root->left, umur);
    return root;
}

void printAll(struct data* root){
    if(root == NULL) return;
    printAll(root->left);
    printf("%d\n",root->umur);
    printAll(root->right);
}

struct data* minValue(struct data* root){
    while(root->left!=NULL){
        root = root->left;
    }
    return root;
}

struct data* delete(struct data* root,int umur){
    if(root == NULL) printf("Tidak ada data\n");
    else if(umur > root->umur) root->right = delete(root->right, umur);
    else if(umur < root->umur) root->left = delete(root->left, umur);
    else{
        if(root->left == NULL && root->right == NULL){
            free(root);
            root = NULL;
        }
        else if(root->left == NULL){
            struct data* temp = root;
            root = root->right;
            free(temp);
        }
        else if(root->right == NULL){
            struct data* temp = root;
            root = root->left;
            free(temp);
        }
        else{
            struct data* temp = minValue(root->right);
            root->umur = temp->umur;
            root->right = delete(root->right, temp->umur);
        }
    }
    return root;
}

oke selesai materi review kali ini, oke saya kasih contoh kasus atau case : Shop Case, kita dimampukan untuk membeli barang, mengedit jumlah barang, dan menghapus barang. Semua barang yang kita beli akan otomatis tersorting.

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <time.h>

int totalBarang = 0;

struct Shop{
char barang[100];
int Qty;
int harga;

Shop *prev, *next;
}*head,*tail;

struct Shop *newShop(const char *barang, int Qty)
{
Shop *curr = (Shop *)malloc(sizeof(Shop));
strcpy(curr->barang,barang);
curr->Qty = Qty;
curr->harga = (rand()%100)*1000;
curr->next = NULL;
curr->prev = NULL;
return curr;
}

void pushShop(Shop *curr)
{
if(head==NULL)
{
head=tail=curr;
}
else if (strcmp(curr->barang,head->barang)<0)
{
curr->next = head;
head->prev = curr;
head = curr;
}
else if(strcmp(curr->barang,tail->barang)>0)
{
tail->next = curr;
curr->prev = tail;
tail = curr;
}
else
{
Shop *temp = head;
while(strcmp(curr->barang,temp->barang)>0)
{
temp = temp->next;
}
curr->next = temp;
curr->prev = temp->prev;
temp->prev->next = curr;
temp->prev = curr;
}
}

void update(int ID, int Qty)
{
Shop *temp = head;
int count = 1;
while(count != ID)
{
temp = temp->next;
count++;
}
temp->Qty = Qty;
temp->harga = (rand()%100)*1000;
}

void Delete(int input)
{
int count = 1;
Shop *temp = head;
if(input == 1)
{
if(head==tail)
{
head=NULL;
free(temp);
}
else
{
head = head->prev;
head->prev = NULL;
free(temp);
temp = NULL;
}
}
else if(input == totalBarang && totalBarang != 1)
{
temp = tail;
tail = tail->prev;
tail->next = NULL;
free(temp);
temp = NULL;
}
else
{
while(count != input-1)
{
temp = temp->next;
count++;
}
Shop *curr = temp->next = curr->next;
temp->next->prev = temp;
free(curr);
curr = NULL;
}
totalBarang--;
}

void cetak()
{
int count = 1;
while(head!=NULL)
{
printf("%-15d | %-20s | %-5d | %-7d\n",count,head->barang,head->Qty,head->harga);
head = head->next;
count++;
}
puts("");
}

void buy()
{
system("cls");
char barang[100];
int Qty;
printf("Input Produk Nama: ");
scanf("%[^\n]",barang);getchar();
printf("Input Produk Qty: ");
scanf("%d",&Qty);getchar();

pushShop(newShop(barang,Qty));
printf("Data berhasil ditambahkan\n");
totalBarang++;
getchar();
}

void DeleteBarang()
{
system("cls");
int ID;
cetak();
printf("Input Id to deleted: ");
scanf("%d",&ID);
Delete(ID);
printf("Item berhasil di delete\n");getchar();
}

void editBarang(){
system("cls");
int ID;
int Quality;
cetak();
printf("Input Id to updated: ");
scanf("%d", &ID) ; getchar();
printf("Input new quantity: ");
scanf("%d", &Quality) ; getchar();
update(ID,Quality);
printf("Item berhasil di update\n") ; getchar() ;
}

void PrintHasil()
{
system("cls");
printf("Jumlah Harga\n");
printf("==============\n");
cetak();
printf("Total: \n");
printf("Harga Free\n");getchar();
Shop *temp = head ;
while(temp != NULL){
Shop *curr = temp ;
temp = temp->next ;
free(curr) ;
curr=NULL;
}
exit(0);
}

int main()
{
srand(time(0));

int chose;
do
{
printf("Rizki Ashari Shop\n");
printf("====================\n");
cetak();
printf("1. Buy Item\n");
printf("2. Edit Item Qty\n");
printf("3. Delete Item\n");
printf("4. Print Bill\n");
printf("5. Exit\n");
printf("Choose >> ");
scanf("%d",&chose);getchar();
if(chose == 1)
{
buy();
}
else if(chose == 2)
{
editBarang();
}
else if(chose == 3)
{
DeleteBarang();
}
else if(chose == 4)
{
PrintHasil();
}
else if(chose == 5)
{
printf("Thank You to Order\n");
}
}while(chose!=5);
return 0;

}

sumber materi : PPT BINUS

Tuesday, March 17, 2020

Binary Search Tree

Materi kali saya akan  membahas mengenai Binary Search Tree, yang saya terima dari dosen saya yang tercinta hehe sedikit lebay gapapa ya, dosen Henry Chong dan berbagai sumber yang saya dapatkan di internet, ah jadi berbelit-belit gini kan yaudah sorry ya, gue cepetin deh ke materi ya, okee cikedoot couuuyy

Binary Search Tree ialah yang terurut (ordered Binary Tree). Binary Search Tree juga sering disebut dengan Sorted Binary Tree yang berfungsi untuk menyimpan informasi nama atau bilangan yang disimpan di dalam memory.

di Binary Search Tree/BST ini memiliki induk atau sering disebut root, dan memiliki anak akar, sibling dll. 

Binary search tree memungkinkan pencarian dengan cepat, penambahan, juga menghapus data yang ada di dalamnya, bisa juga digunakan sebagai implementasi sejumlah data dinamis, atau pencarian table data dengan menggunakan informasi kunci atau key.
Agar data benar-benar tersusun dalam struktur data BST, dua aturan yang harus dipenuhi pada saat data diatur dalam BST adalah sebagai berikut:

- Semua data dibagian kiri sub-tree dari node t selalu lebih kecil dari data dalam node utama itu        sendiri.
- Semua data dibagian kanan sub-tree dari node t selalu lebih besar atausama dengan data dalam node utama.


di BST ini memiliki 3 operasi dasar yaitu:
1. Remove : memasukan value baru x ke BST ( Push ).
2. Find : find value x didalam BST ( Search ).
3. Insert : menghapus key x dari BST ( Delete ).

Operasi : Find BST

Dengan adanya ciri” atau syarat di dalam BST , maka untuk finding/searching didalam BST menjadi lebih mudah. Bayangkan kita mencari value x.
  • Memulai Pencarian Dari Root
  • Jika Root adalah value yang kita cari , maka berhenti
  • Jika x lebih kecil dari root maka cari kedalam rekrusif tree sebelah kiri
  • Jika x lebih besar dari root maka cari kedalam rekrusif tree sebelah kanan

Operasi: Insertion BST

Memasukan value (data) baru kedalam BST dengan rekrusif
Bayangkan kita menginsert value x :
  • Dimulai dari root
  • jika x lebih kecil dari node value(key) kemudian cek dengan sub-tree sebelah kiri lakukan pengecekan secara berulang ( rekrusif )
  • jika x lebih besar dari node value(key) kemudian cek dengan sub-tree sebelah kanan lakukan pengecekan secara berulang ( rekrusif )
  • Ulangi sampai menemukan node yang kosong untuk memasukan value X ( X akan selalu berada di paling bawah biasa di sebut Leaf atau daun )

Operasi: Delete

akan ada 3 case yang ditemukan ketika ingin menghapus yang perlu diperhatikan :
  • Jika value yang ingin dihapus adalah Leaf(Daun) atau paling bawah , langsung delete
  • Jika value yang akan dihapus mempunyai satu anak, hapus nodenya dan gabungkan anaknya ke parent value yang dihapus
  • jika value yang akan di hapus adalah node yang memiliki 2 anak , maka ada 2 cara , kita bisa cari dari left sub-tree anak kanan paling terakhir(leaf) (kiri,kanan).
okee segitu dulu yak materi kali ini sekian dah terima kasih


Sumber :
https://sourcecodegeneration.blogspot.com/2018/08/pengertian-binary-tree-binary-search.html
https://abdilahrf.github.io/2015/06/pengenalan-binary-search-tree/

Tuesday, March 10, 2020

Hashing Table and Binary Search Tree

Pada kesempatan kali ini saya, ingin memaparkan penjelasan mengenai Hashing Table dan Binar Search Tree, okee kalau gitu saya tidak berlama-lama, langsung ke topik permasalahan nya, cikedotttttttt



A. Hashing Table
Apa si Hashing Table? Hash table merupakan salah satu struktur data yang digunakan dalam penyimpanan data sementara, tujuan dari hash table adalah untuk mempercepat pencarian kembali dari banyak data yang disimpan.
Kelebihan Hashing Table ialah
1. Lebih Cepat mengakses Data.
2. Kecepatan dalam insertions, deletions, maupun searching relatif samaKecepatan dalam insertions, deletions, maupun searching relatif sama.
Yang perlu diperhatikan untuk membuat hash function adalah:
  1. ukuran array/table size(m),
  2. key value/nilai yang didapat dari data(k),
  3. hash value/hash index/indeks yang dituju(h).
contoh penggunaan hash table dengan hash function sederhana yaitu memodulus key value dengan ukuran array : h = k (mod m). Misal kita memiliki array dengan ukuran 13, maka hash function : h = k (mod 13).
Dengan hash function tersebut didapat :
Perhatikan range dari h untuk sembarang nilai k.
Maka data 7 akan disimpan pada index 7, data 13 akan disimpan pada index 0, dst..
Untuk mencari kembali suatu data, maka kita hanya perlu menggunakan hash function yang sama sehingga mendapatkan hash index yang sama pula.
Misal : mencari data 25 → h = 25 (mod 13) = 12
Namun pada penerapannya, seperti contoh di atas terdapat tabrakan (collision) pada k = 13 dan k = 39. Collision berarti ada lebih dari satu data yang memiliki hash index yang sama, padahal seperti yang kita ketahui, satu alamat / satu index array hanya dapat menyimpan satu data saja.
Cara mengatasi Collision Sebagai berikut:
1.   Closed hashing (Open Addressing).
Close hashing menyelesaikan collision dengan menggunakan memori yang masih ada tanpa menggunakan memori diluar array yang digunakan. Closed hashing mencari alamat lain apabila alamat yang akan dituju sudah terisi oleh data. 3 cara untuk mencari alamat lain tersebut 
   - Linear Probing
Apabila telah terisi, linear probing mencari alamat lain dengan bergeser 1 indeks dari alamat sebelumnya hingga ditemukan alamat yang belum terisi data, dengan rumus (h+1) mod m.
   - Quadratic Probing
Quadratic Probing mencari alamat baru untuk ditempati dengan proses perhitungan kuadratik yang lebih kompleks. Tidak ada formula baku pada quadratic probing ini,anda dapat menentukan sendiri formula yang akan digunakan. Contoh formula quadratic probing untuk mencari alamat baru: h,(h+i2)mod m,(h-i2)mod m, … ,(h+((m-1)/2)2)mod m, (h-((m-1)/2)2)mod m, dengan i = 1,2,3,4, … , ((m-1)/2). Maksud formula di atas adalah jika alamat h telah terisi, maka alamat lain yang digunakan adalah (h+1)mod m, jika telah terisi gunakan alamat (h-1)mod m,  jika telah terisi gunakan alamat (h+4)mod m, jika telah terisi gunakan alamat (h-4)mod m, dan seterusnya. Jadi jika m=23,maka nilai maksimal i adalah : ((23-1)/2)=11.
    - Double hashing
Sesuai dengan namanya, alamat baru untuk menyimpan data yang belum dapat masuk ke dalam table diperoleh dengan menggunakan hash function lagi. Hash function kedua yang digunakan setelah alamat yang dihasilkan oleh hash function awal telah terisi tentu saja berbeda dengan hash function awal itu sendiri. Kelemahan dari closed hashing adalah ukuran array yang disediakan harus lebih besar dari jumlah data. Selain itu dibutuhkan memori yang lebih besar untuk meminimalkan collision.
2.   Open hashing (Separate Chaining)
Pada dasarnya separate chaining membuat tabel yang digunakan untuk proses hashing menjadi sebuah array of pointer yang masing-masing pointernya diikuti oleh sebuah linked list, dengan chain (mata rantai) 1 terletak pada array of pointer, sedangkan chain 2 dan seterusnya berhubungan dengan chain 1 secara memanjang.
Penggunaan Hashing pun terdapat di sistem blockhain, hashing menggunakan sistem cryptocurrency.
B. Binary Search Tree
Binary Search Tree adalah struktur data yang mengadopsi konsep Binary Tree namun terdapat aturan bahwa setiap clild node sebelah kiri selalu lebih kecil nilainya dari pada root node. Begitu pula sebaliknya, setiap child node sebelah kanan selalu lebih besar nilainya daripada root node.

Aturan main Binary Search Tree :

- Setiap child node sebelah kiri harus lebih kecil nilainya daripada root nodenya.
- Setiap child node sebelah kanan harus lebih besar nilainya daripada root nodenya.
Lalu ada 3 Sistem dalam Binary Search Tree, yaitu: 
PreOrder : Print data, telusur ke kiri, telusur ke kanan
- InOrder : Telusur ke kiri, print data, telusur ke kanan
- Post Order : Telusur ke kiri, telusur ke kanan, print data

//preOrder : cetak, kiri, kanan
void preOrder(data **current){
 if((*current)!=NULL){
  printf("%d -> ", (*current)->number);
  preOrder(&(*current)->left);
  preOrder(&(*current)->right);
 }
}

//inOrder : kiri, cetak, kanan
void inOrder(data **current){
 if((*current)!=NULL){
  inOrder(&(*current)->left);
  printf("%d -> ", (*current)->number);
  inOrder(&(*current)->right);
 }
}

//postOrder : kiri, kanan, cetak
void postOrder(data **current){
 if((*current)!=NULL){
  postOrder(&(*current)->left);
  postOrder(&(*current)->right);
  printf("%d -> ", (*current)->number);
 }
}

Sumber : 

Tuesday, March 3, 2020

Linked List II

Linked List II

-Double Linked List

Double Linked List ialah sekumpulan node data yang terurut linear atau sekuensial dengan dua buah pointer yaitu prev dan next.

Double Linked memiliki proses Insert, Delete dan Search
1. Insert
Insert terbagi dua yaitu, Insert belakang dan Insert Depan
  a. Insert Belakang : Penyisipan di awal list, sehingga pointer head juga akan berpindah ke elemen baru.
if(head == NULL)
{
head=tail=curr;
}
else
{
tail->next=curr;
curr->prev=tail;
tail=curr;
}

  b. Insert Depan : Penyisipan di akhir list, sehingga pointer tail juga akan berpindah ke elemen baru.

if(head == NULL)

head=tail=curr;
}
else
{
head->prev=curr;
curr->next=head;
head=curr;
}

2. Delete
 Delete terbagi dua yaitu, Delete Depan, Delete Belakang.
a. Delete Depan : penghapusan di awal list, pointer head akan berpindah ke node selanjutnya,sementara node awal akan di alokasi.
if(head == tail){
head=tail=NULL;
free(head);
}
else{
data *temp=head;
head=head->next;
head->prev=NULL;
temp->next=NULL;
free(temp);
}
b, Delete belakang :Penghapusan di akhir list, pointer tail akan berpindah ke node sebelumnya,sementara node akhir akan di alokasi.

if(head==tail)
{
  head=tail=NULL;
        free(head);
 }
 else
{
  data *temp=tail;
        tail=tail->prev;
        tail->next=NULL;
        temp->prev=NULL;
        free(temp);
}

3. Search itu mencari dan mengurutkan nilai terkecil hingga terbesar atau sebaliknya. Search pun terbagi dua, search Insert dan search delete
Search Delete jika di implementasikan ke bahasa C yaitu:
if(head==NULL){ //kondisi 1
printf("No Data!\n");
}
else if(head==tail){ //kondisi 2
head=tail=NULL;
free(head);
}
else if(head->angka==curr->angka){ //kondisi 3
popHead();
}
else if(tail->angka==curr->angka){ //kondisi 4
popTail();
}
else{
data *temp=head; //kondisi 5
while(temp!=NULL){
if(temp->angka==curr->angka){
break;
}
temp=temp->next;
}
temp->next->prev=temp->prev;
temp->prev->next=temp->next;
temp->next=NULL;
temp->prev=NULL;
free(temp);

}

Search Insert jika di implementasikan ke bahasa C yaitu:
if(head == NULL)
{
head=tail=curr;
}
else if(curr->angka < head->angka)
{
pushHead(curr);
}
else if(curr->angka > tail->angka)
{
pushTail(curr);
}
else
{
data *temp=head;
while(temp->next->angka < curr->angka)
        {
temp=temp->next;
}
curr->next=temp->next; //1
temp->next->prev=curr; //2
temp->next=curr; // 3
curr->prev=temp; // 4

}


Sumber:
PPT BINUS
https://rizkidoank.com/2016/10/17/double-linked-list/

Visualisasi data

 Selamat Datang Perkenalkan kami dari Universitas Bina Nusantara dari Jurusan Computer Science yang beranggotakan  Rizki Ashari,  Kenisya Fu...