• Tidak ada hasil yang ditemukan

BAB I ALGORITMA DAN STRUKTUR DATA

N/A
N/A
Protected

Academic year: 2021

Membagikan "BAB I ALGORITMA DAN STRUKTUR DATA"

Copied!
102
0
0

Teks penuh

(1)

1

BAB I

ALGORITMA DAN STRUKTUR DATA

1.1 Pendahuluan

Deskripsi singkat : Bab ini menjelaskan tentang konsep dasar algoritma dan struktur data meliputi: definisi algoritma dan struktur data, struktur data statis dan dinamis serta tipe data abstrak.

Manfaat : Mahasiswa mampu memahami tentang konsep dasar algoritma dan struktur data serta implementasinya.

Relevansi : Konsep dasar algoritma merupakan dasar yang penting untuk materi materi selanjutnya.

Learning Outcomes : Mahasiswa Memiliki pengetahuan mengenai teori dan konsep dasar algoritma dan struktur data.

Alokasi dan waktu : Bahan yang ada pada bab ini membutuhkan alokasi waktu kurang lebih 150 menit, dan disampaikan pada minggu pertama perkuliahan.

Definisi : Algoritma dan Struktur Data

Algoritma adalah urutan logis langkah-langkah untuk menyelesaikan masalah. Algoritma memiliki lima ciri penting :

1. Algoritma harus berhenti setelah mengerjakan sejumlah langkah terbatas. 2. Setiap langkah harus didefinisikan dengan tepat dan tidak ambigu (definite). 3. Algoritma memiliki nol atau lebih masukan.

4. Algoritma memiliki satu atau lebih keluaran. 5. Algoritma harus efektif.

Struktur data: susunan atau cara merepresentasikan data agar efisien dalam penyimpanan (RAM) dan pengolahannya. Struktur data seharusnya dapat diterapkan pada algoritma yang didesain secara efisien

Jadi mata kuliah Algoritma & Struktur Data adalah suatu disiplin ilmu yang mempelajari bagaimana merepresentasikan data secara efisien dan desain pengolahannya secara efisien pula.

(2)

2 Ide pemrograman terstruktur pertama kali disampaikan oleh Profesor Edsger Djikstra dari Universitas Eidenhower sekitar tahun 1965. Djikstra mengusulkan tidak dipergunakannya pernyataan GOTO yang dapat menyebabkan timbulnya “spaghetti logic”, yang akan menjadikan sulitnya dilakukan perbaikan ataupun pengembangan program. Kemudian HD Millis menanggapi dengan mengemukakan bahwa pemrograman terstruktur tidak hanya dihubungkan dengan tidak digunakannya pernyataan GOTO, akan tetapi juga dengan struktur dari program. Struktur program yang akan menentukan program yang terstruktur menggunakan pernyataan GOTO atau tidak.

Prinsip utama dari pemrograman terstruktur ialah bahwa jika suatu proses telah sampai pada suatu titik tertentu, maka proses selanjutnya tidak boleh melompat ke baris sebelumnya, kecuali untuk proses berulang. Pemrograman terstruktur dimaksud untuk mendapatkan program yang didefinikan dengan baik, jelas, mudah dipahami, mudah ditelusuri, dan mudah dimodifikasi.

Langkah-langkah penyelesaian masalah dengan algoritma dan pemrograman adalah sebagai berikut :

1. Analisis masalah

2. Desain algoritma, meliputi :  Deskripsi (cara penulisan):

o natural language o pseudo-code

o diagram (seperti flowchart)  Kriteria algoritma:

o Input: nol atau lebih o Output: satu atau lebih

o Definisi/terjemahan/interprestasi: jelas, tepat untuk tiap instruksi

o Batasan: sebuah algoritma harus berhenti setelah sejumlah langkah, walaupun jumlah langkah boleh banyak tapi harus terbatas

 Efektifitas: tiap instruksi harus berupa perintah dasar bukan merupakan bentukan dari beberapa perintah

(3)

3  Space complexity

o Berapa banyak space yang dibutuhkan  Time complexity

o Berapa lama waktu running algoritma 4. Implementasi

 Pemutusan bahasa pemrograman yang akan digunakan o C, C++, Lisp, Java, Perl, Prolog, assembly, dll.

 Penulisan koding harus terdokumentasi dengan baik dan jelas. 5. Ujicoba

Mengintegrasikan feedback dari user, perbaiki bug, penjaminan kompatibelitas pada berbagai platform

6. Pemeliharaan

1.2 Struktur Data Statis dan Dinamis

Struktur data dilihat dari kebutuhan memorynya dapat dikelompokan menjadi 2 macam yaitu struktur data statis dan dinamis, dimana

 Struktur data statis : Struktur data yang kebutuhan/alokasi memorinya tetap (fixed size), tidak dapat dikembangkan atau diciutkan, biasanya menggunakan tipe data array

 Struktur data dinamis : Struktur data yang kebutuhan memorynya sesuai data yang ada, dimana dapat dikembangkan atau diciutkan sesuai dengan kebutuhan. Pengelolaan alamat secara dinamis (dynamic address) dapat dilakukan dengan menggunakan tipe data pointer.

Pemakaian array tidak selalu tepat untuk program-program terapan yang kebutuhan pengingatnya selalu bertambah selama eksekusi program tersebut. Untuk itu diperlukan satu tipe data yang dapat digunakan untuk mengalokasikan (membentuk) dan mendealokasikan (menghapus) pengingat secara dinamis, yaitu sesuai dengan kebutuhan pada saat suatu program dieksekusi. Oleh karena itu akan dijelaskan suatu tipe data yang dinamakan sebagai tipe Data Pointer.

(4)

4 Nama peubah yang kita gunakan untuk mewakili suatu nilai data sebenarnya merupakan / menunjukkan suatu lokasi tertentu dalam RAM di mana data yang diwakili oleh tipe data tersebut disimpan. Pada saat sebuah program dikompilasi maka compiler akan melihat pada bagian deklarasi peubah untuk mengetahui nama-nama peubah apa saja yang digunakan, sekaligus mengalokasikan atau menyediakan tempat dalam memory untuk menyimpan nilai data tersebut. Dari sini kita bisa melihat bahwa sebelum program dieksekusi, maka lokasi-lokasi data dalam memory sudah ditentukan dan tidak dapat diubah selama program tersebut dieksekusi. Peubah-peubah yang demikian itu dinamakan sebagai Peubah

Statis (Static Variable).

Dari pengertian diatas kita perhatikan bahwa sesudah suatu lokasi pengingat ditentukan untuk suatu nama peubah maka dalam program tersebut peubah yang dimaksud akan tetap menempati lokasi yang telah ditentukan dan tidak mungkin diubah. Dengan melihat pada sifat-sifat peubah statis maka bisa dikatakan bahwa banyaknya data yang bisa diolah adalah sangat terbatas. Misalnya peubah dalam bentuk Array yang dideklarasikan sbb : int matriks[100][100], maka peubah tersebut hanya mampu menyimpan data sebanyak 100x100=10000 buah data. Jika kita tetap nekat memasukkan data pada peubah tersebut setelah semua ruangnya penuh maka eksekusi program akan terhenti dan muncul error. Memang kita dapat mengubah deklarasi program diatas dengan memperbesar ukurannya. Tetapi jika setiap kali kita harus mengubah deklarasi dari tipe daa tersebut sementara, banyaknya data tidak dapat ditentukan lebih dahulu, maka hal ini tentu merupakan pekerjaan yang membosankan.

Sekarang bagaimana jika kita ingin mengolah data yang banyaknya kita tidak yakin sebelumnya bahwa larik yang telah kita deklarasikan sebelumnya mampu menampung data yang kita miliki ? Untuk menjawab pertanyaan di atas maka pascal menyediakan satu fasilitas yang memungkinkan kita untuk menggunakan suatu peubah yang disebut dengan Peubah

Dinamis (Dynamic Variable). Peubah dinamis adalah peubah yang dialokasikan hanya pada

saat diperlukan, yaitu setelah program dieksekusi. Dengan kata lain, pada saat program dikompilasi, lokasi untuk peubah belum ditentukan sebagai peubah dinamis. Hal ini membawa keuntungan pula, bahwa peubah-peubah dinamis tersebut dapat dihapus pada saat

(5)

5 program dieksekusi sehingga ukuran memory selalu berubah. Hal inilah yang menyebabkan peubah tersebut dinamakan sebagai peubah dinamis.

Pada peubah statis, isi dari peubah adalah data sesungguhnya yang akan diolah. Pada peubah dinamis nilai peubah adalah alamat lokasi lain yang menyimpan data sesungguhnya. Dengan demikian data yang sesungguhnya tidak dapat dimasup secara langsung. Oleh karena itu, peubah dinamis dikenal dengan sebutan POINTER yang artinya menunjuk ke sesuatu, yang berisi adress/alamat dalam RAM.

Deklarasi variabel bertipe pointer : tipe data *namavariabel;

Contoh : int *p

Maka variabel p menunjuk suatu alamat pada memori. Jika ada variabel A bertipe integer, maka alamat variabel tersebut pada memori bisa diketahui dengan pernyataan &A. Variabel pointer p, bisa menunjuk ke alamat variabel A, yaitu dengan pernyataan :

p = &A;

atau dengan memesan sendiri memory baru yaitu dengan perintah p = new int;

Sedangkan untuk mengetahui isi dari variabel yang alamatnya ditunjuk oleh p, dengan pernyataan *p;

Contoh Program menuliskan alamat dan nilai dari suatu variabel pointer :

#include<iostream> using namespace std; main(){ int a,*b; a=10; b=&a; c=new int; *c=25; cout<<b<<" "<<*b<<" "<<c; getchar(); }

(6)

6

1.3 Tipe Data Abstrak

Menurut Wikipedia, Tipe data abstrak (TDA) atau lebih dikenal dalam bahasa Inggris sebagai Abstract data type (ADT) merupakan model matematika yang merujuk pada sejumlah bentuk struktur data yang memiliki kegunaan atau perilaku yang serupa; atau suatu tipe data dari suatu bahasa pemrograman yang memiliki sematik yang serupa. Tipe data abstrak umumnya didefinisikan tidak secara langsung, melainkan hanya melalui operasi matematis tertentu sehingga membutuhkan penggunaan tipe data tersebut meski dengan resiko kompleksitas yang lebih tinggi atas operasi tersebut.

Dengan kata lain Tipe data abstrak (ADT) dapat didefinisikan sebagai model matematika dari objek data yang menyempurnakan tipe data dengan cara mengaitkannya dengan fungsi-fungsi yang beroprasi pada data yang bersangkutan. Merupakan hal yang sangat penting untuk mengenali bahwa operasi-operasi yang akan dimanipulasi data pada objek yang bersangkutan termuat dalam spesifikasi ADT. Sebagai contoh, ADT HIMPUNAN didefinisikan sebagai koleksi data yang diakses oleh operasi-operasi himpunan seperti penggabungan (UNION), irisan (INTERSECTION), dan selisih antar-himpunan (SET DIFFERENCE).

Implementasi dari ADT harus menyediakan cara tertentu untuk merepresentasikan unsur tipe data (seperti matrix) dan cara untuk mengimplementasikan operasi -operasi matrix. Secara tipikal, kita akan mendeskripsikan operasi-operasi pada ADT dengan algoritma (logika berfikir) tertentu. Algoritma ini biasanya berupa urutan instruksi yang menspesifikasi secara tepat bagaimana operasi-operasi akan dilakukan/dieksekusi oleh komputer.

Kita sekarang akan membahas lebih konkret tentang apa itu ADT. Pada dasarnya, ADT adalah tipe data tertentu yang didefinisikan oleh pemrogram untuk kemudahan pemrograman serta untuk mengakomodasi tipe-tipe data yang tidak secara spesifik diakomodasi oleh bahasa pemrograman yang digunakan. Maka, secara informal dapat dinyatakan bahwa ADT adalah :

1. Tipe data abstrak ADT pertama kali ditemukan oleh para ilmuan komputer utuk memisahkan struktur penyimpanan dari perilaku tipe data yang abstrak seperti misalnya, Tumpukan(Stack) serta antrian(Queue). Seperti kita duga, pemrogram tidak perlu tahu bagaimana

(7)

7 Tumpukan(Stack) perubahan inplementasi ADT tidak mengubah program yang menggunakannya secara keseluruhan, dengan catatan bahwa interface ADT tersebut dengan ‘dunia luar’ tetap dipertahankan.

2. Pemakaian dan pembuatan ADT dapat dilakukan secara terpisah. yang perlu dibicarakan antara pembuat dan pengguna ADT adalah interface ADT yang bersangkutan.

3. ADT merupakan sarana pengembangan sistem yang bersifat modular, memungkinkan suatu sistem dikembangkan oleh beberapa orang anggota tim kerja dimana masing-masing anggota tim bisa melakukan bagiannya sendiri-sendiri dengan tetap mempertahankan keterpaduannya dengan anggota tim yang lain.

Dalam hal ini perlu dibedakan antara pengertian struktur data dan ADT. Struktur data hanya memperlihatkan bagaimana data-data di organisir, sedangkan ADT bercakupan lebih luas, yaitu memuat/mengemas struktur data tertentu sekaligus dengan operasi-operasi yang dapat dilakukan pada struktur data tersebut. Dengan demikian, definisi umum tentang ADT di atas dapat diperluas sebagai berikut :

Implementasi ADT=

{Struktur Data (Operasi-operasi yang dapat dilakukan terhadap Struktur Data)} Contoh ADT

Tipe jadi (built-in): boolean, integer, real, array, dll

Tipe buatan (user-defined): stack, queue, tree, dll

ADT Built-in: Boolean

Nilai: true dan false

Operasi: and, or, not, xor, dll Integer

Nilai: Semua bilangan

(8)

8

ADT buatan (user-defined) :

Stack (tumpukan)

Nilai : elemen dalam stack Operasi: Initstack, Push, Pop

Queue (antrian)

Nilai: elemen dalam Queue

Operasi: InitQueue, Enqueue, Dequeue.

Tree (pohon)

Nilai: elemen dalam pohon

Operasi: insert, delete, find, traverse

(9)

9

1.4 Latihan Soal

1. Tulislah output dari cuplikan program berikut : #include<iostream> using namespace std; main(){ int a,*b, *c; a=10; b=&a; cout<<*b<<endl; c=new int; *c=25; b=c; cout<<*b<<endl; getchar(); }

2. Diketahui subprogram berikut : void buatA(list &l)

{ int i,n; list b,t; n=10;

for (i=1;i<=n;i++){

b=new node; b->next=NULL; b->data=(i+i*i*2)%40; cout<<b->data<<" "; if (l==NULL) l=b;

else if (b->data%2==0) {b->next=l;l=b;} else {

t=l;

while (t->next!=NULL) t=t->next; t->next=b; } } } Jika dipanggil list p; BuatA(p); cetakdata(p); Maka tulis outputnya.

(10)

10

BAB II

STRUKTUR DATA LINEAR

2.1 Pendahuluan

Deskripsi singkat : Bab ini menjelaskan tentang struktur data linear yang meliputi: larikan, single linked list, doubly linked list serta stack dan queue.

Manfaat : Mahasiswa memahami tentang berbagai macam struktur data linear dan dapat mengimplementasikan pada beberapa permasalahan.

Relevansi : Struktur data linear paling banyak digunakan dalam menyelesaikan masalah pemrograman dan akan merupakan dasar dari struktur data yang lebih kompleks.

Learning Outcomes : Mahasiswa Dapat menganalisis, merancang dan mengimplementasikan struktur data linear seperti linked list, stack dan queue.

Alokasi dan waktu : Bahan yang ada pada bab ini membutuhkan alokasi waktu kurang lebih 600 menit, dan disampaikan pada minggu kedua sampai minggu kelima perkuliahan.

Definisi : Struktur data linear adalah kumpulan komponen-komponen yang tersusun membentuk satu garis linear. Bila komponen-komponen ditambahkan (atau dikurangi), maka struktur-struktur tersebut berkembang (atau menyusut). Pemakaian struktur data yang tepat di dalam proses pemrograman akan menghasilkan algoritma yang lebih jelas dan tepat , sehingga menjadikan program secara keseluruhan lebih efisien dan sederhana.

Struktur data linear yang akan dibahas adalah Larikan, yaitu menggunakan array 1 dimensi, linear linked list serta stack dan queue.

2.2 Larikan, Array Satu Dimensi

Array adalah suatu struktur yang terdiri dari sejumlah elemen yang memiliki tipe data yang sama. Elemen-elemen array tersusun secara sekuensial dalam memori komputer. Array dapat berupa satu dimensi, dua dimensi, tiga dimensi ataupun banyak dimensi (multi dimensi).

Larikan dibentuk menggunakan Array Satu dimensi, yaitu tidak lain adalah kumpulan elemen-elemen identik yang tersusun dalam satu baris. Elemen-elemen tersebut memiliki tipe data yang sama, tetapi isi dari elemen tersebut bisa berbeda.

(11)

11

Elemen ke- 0 1 2 3 4 5 6 7 8 9

Nilai 23 34 32 12 25 14 23 12 11 10

Berikut contoh program mengisi larik X dengan bilangan random kemudian menentukan maximum dan minimum.

#include<iostream> #include<stdlib.h> #include<conio.h> using namespace std;

main() {

int i, n, max, min, x[100];

cout<<"masukkan banyak data : ";cin>>n; srand((unsigned)time(NULL)); for (i=1;i<=n;i++) { x[i]=rand()%100+1; cout<<x[i]<<" "; if (i%10==0) cout<<endl; } cout<<endl; max=x[1];min=x[1]; for (i=2;i<=n;i++){ if (x[i]>max) max=x[i]; else if(x[i]<min) min=x[i]; }

cout<<"data max adalah : "<<max<<endl; cout<<"data min adalah : "<<min<<endl; }

2.3 Linear Linked List

Pada bab sebelumnya telah dijelaskan mengenai variabel array yang bersifat statis (ukuran dan urutannya sudah pasti). Selain itu, ruang memori yang dipakai olehnya tidak dapat dihapus bila array tersebut sudah tidak digunakan lagi pada saat program dijalankan. Untuk memecahkan masalah di atas, kita dapat menggunakan variabel pointer. Tipe data pointer bersifat dinamis, variabel akan dialokasikan hanya pada saat dibutuhkan dan sesudah tidak dibutuhkan dapat direlokasikan kembali.

Setiap ingin menambahkan data, Anda selalu menggunakan variabel pointer yang baru, akibatnya Anda akan membutuhkan banyak sekali pointer. Oleh karena itu, ada baiknya

(12)

12 jika Anda hanya menggunakan satu variabel pointer saja untuk menyimpan banyak data dengan metode yang kita sebut Linked List. Linked list adalah sekumpulan elemen bertipe sama, yang mempunyai keterurutan tertentu, yang setiap elemennya terdiri dari dua bagian.

Untuk dapat menyimpan data yang banyak dan untuk menunjukan sifat dinamisnya, maka variabel pointer harus dikombinasikan dengan tipe data struct, yaitu membentuk struktur data linked list (senarai berantai), berikut contoh deklarasi dan subprogram untuk membentuk linked list dari data random dengan menggunakan metode insert di depan, sebagai berikut :

typedef struct node { int data;

struct node *next; } *list;

list L;

void buatD(list &l) {

int i,n; list b;

cout<<"banyak data : ";cin>>n; srand((unsigned)time(NULL)); for (i=1;i<=n;i++){ b=new node; b->next=NULL; b->data=rand()%100+1; cout<<b->data<<" "; if (l==NULL) l=b; else {b->next=l; l=b;} } } void cetakdata(list l) { list p; if (l!=NULL) { p=l;

while (p!=NULL) {cout<<p->data<<" ";p=p->next;} } else cout<<"kosong"; } int main() { int x; list p; p=NULL;

(13)

13 buatD(p); cetakdata(p); getch(); return 0; }

Pembuatan Linear Linked List dapat menggunakan beberapa cara yaitu :

1. Insert depan, yaitu data yang baru masuk menjadi data atau node paling depan

2. Insert Belakang, yaitu data yang baru masuk menjadi data atau node paling belakang. 3. Insert Terurut, yaitu data yang baru masuk disisipkan pada tempatnya sehingga

keseluruhan data dijaga selalu terurut.

Linear linked list dari banyaknya linked ada 2 macam, yaitu single linked list dan double linked list.

1. Single Linked List

Pada gambar di atas adalah contoh gambaran tentang single linked list L, setiap node memiliki pointer yang menunjuk ke simpul berikutnya sehingga terbentuk satu untaian, dengan demikian hanya diperlukan sebuah variabel pointer. Susunan berupa untaian semacam ini disebut Single Linked List, NULL memilik nilai khusus yang artinya tidak menunjuk ke mana-mana. Biasanya Linked List pada titik akhirnya akan menunjuk ke NULL.

2. Double Linked List

Salah satu kelemahan single linked list adalah pointer (penunjuk) hanya dapat bergerak satu arah saja, maju/ mundur, atau kanan/kiri sehingga pencarian data pada single linked list hanya dapat bergerak dalam satu arah saja. Untuk mengatasi kelemahan tersebut, anda dapat menggunakan metode double linked list. Linked list ini dikenal dengan nama Linked list berpointer Ganda atau Double Linked List, sehingga dalam mengaksesnya bisa bergerak 2 arah (maju atau mundur), berikut adalah gambaran double linked list

(14)

14 Operasi-Operasi yang ada pada Linked List antara lain adalah sebagai berikut :

Insert

Istilah Insert berarti menambahkan sebuah simpul baru ke dalam suatu linked list.

IsEmpty

Fungsi ini menentukan apakah linked list kosong atau tidak.

Find First

Fungsi ini mencari elemen pertama dari linked list.

Update

Fungsi ini mengubah elemen yang ditunjuk oleh now dengan isi dari sesuatu.

Delete Now

Fungsi ini menghapus elemen yang ditunjuk oleh now. Jika yang dihapus adalah elemen pertama dari linked list (head), head akan berpindah ke elemen berikut.

Delete Head

Fungsi ini menghapus elemen yang ditunjuk head. Head berpindah ke elemen sesudahnya.

2.4 Stack dan Queue.

1. Stack

Stack atau tumpukan adalah struktur data yang berbentuk linear list dengan menggunakan konsep utamanya adalah LIFO (Last In First Out), data yang terakhir masuk dalam stack akan menjadi data pertama yang dikeluarkan dari stack (TOP). Stack ini sering disebut dengan list dengan satu pintu akses. Berikut adalah gambaran tentang Stack.

(15)

15 Setidaknya stack haruslah memiliki operasi-operasi sebagai berikut.

Push Untuk menambahkan item pada tumpukan paling atas Pop Untuk mengambil item teratas

InitStack Untuk memulai atau mengosongkan stack IsEmpty Untuk memeriksa apakah stack kosong IsFull Untuk memeriksa apakah stack sudah penuh

Implementasi stack dalam program dapat digunakan dua cara, yakni dengan array dan linked list.

a. Stack dengan Array

Sesuai dengan sifat stack, pengambilan / penghapusan di elemen dalam stack harus dimulai dari elemen teratas. Berikut contoh program tentang stack dengan array.

#include<iostream> #include<stdio.h> #include<conio.h> using namespace std; const int maxs = 5; typedef struct

{ char isi[maxs+1]; int top;

} stack;

void initstack(stack &S) { S.top = 0;

(16)

16 void push(stack &S,char x)

{ if (S.top<maxs) { S.top++; S.isi[S.top]=x; } else cout<<"Full"; }

void pop(stack &S,char &x) { if (S.top>0) { x=S.isi[S.top]; S.top--; } else cout<<"Empty"; } void PrintStack(stack S) { if (S.top>0) for(int i=S.top;i>0;i--) cout<<S.isi[i]<<endl; else cout<<"kosong"; } main() {stack S; int i,n; char x;

cout<<"The Number of data : ";cin>>n; initstack(S); for (i=1;i<=n;i++) { x=(65+rand()%26); cout<<x<<" "; push(S,x); } cout<<endl; PrintStack(S); cout<<endl; pop(S,x); PrintStack(S); cout<<endl; pop(S,x); PrintStack(S); cout<<endl; x='X'; push(S,x); PrintStack(S); pop(S,x); PrintStack(S); }

(17)

17 b. Stack dengan Single Linked List

Selain implementasi stack dengan array seperti telah dijelasnkan sebelumnya, ada cara lain untuk mengimplementasi stack dalam C++, yakni dengan single linked list. Keunggulannya dibandingkan array tentu saja adalah penggunaan alokasi memori yang dinamis sehingga menghindari pemborosan memori. Misalnya saja pada stack dengan array disediakan tempat untuk stack berisi 150 elemen, sementara ketika dipakai oleh user stack hanya diisi 50 elemen, maka telah terjadi pemborosan memori untuk sisa 100 elemen, yang tak terpakai. Dengan penggunaan linked list maka tempat yang disediakan akan sesuai dengan banyaknya elemen yang mengisi stack. Oleh karena itu pula dalam stack dengan linked list tidak ada istilah full, sebab biasanya program tidak menentukan jumlah elemen stack yang mungkin ada (kecuali jika sudah dibatasi oleh pembuatnya). Namun demikian sebenarnya stack ini pun memiliki batas kapasitas, yakni dibatasi oleh jumlah memori yang tersedia.

Berikut contoh Program Stack dengan linked list: #include<iostream>

#include<conio.h> #include<string.h> using namespace std;

typedef struct node { char data;

struct node *next; } *stack;

void initstack(stack &S) { S = NULL;

}

void push(stack &S,char x) { stack b; b=new node; b->next=NULL; b->data=x; if (S==NULL) S=b; else {b->next=S; S=b;} }

(18)

18 void pop(stack &S,char &x)

{stack t; if (S!=NULL) { x=S->data; t=S; S=t->next; free(t); } else cout<<"Empty"; } void balikkalimat() {int i,pk;char st[20]; stack S;

cout<<"masukkan sebuah kalimat : "; gets(st); pk=strlen(st); initstack(S); for(i=0;i<pk;i++) push(S,st[i]); i=0; do { pop(S,st[i]); i++; } while (S!=NULL);

cout<<"kalimat hasil : "<<st<<endl;

}

void cekbalance() {int i,pk;char x,st[20]; stack S;bool cek;

cout<<"masukkan sederetan expresi : "; gets(st); pk=strlen(st); initstack(S); i=0;cek=1; while (i<pk){ if ((st[i]=='{')||(st[i]=='[')||(st[i]=='(')) push(S,st[i]); else { if (S==NULL) { cek=0;i=pk;}

if (((st[i]=='}')&&(S->data=='{'))|| ((st[i]==']')&&(S->data=='['))|| ((st[i]==')')&&(S->data=='('))) pop(S,x);else if ((st[i]=='}')||(st[i]==']')||(st[i]==')')) {cek=0;i=pk;} }

(19)

19 i++; } if ((S=NULL)||(cek==0)) cout<<"error"; else cout<<"valid"; } main() { balikkalimat(); cekbalance(); getch(); } 2. Queue

Queue atau antrian adalah struktur data yang berbentuk linear list dengan menggunakan konsep utamanya adalah FIFO (First In First Out), data yang pertama masuk dalam queue akan menjadi data pertama yang dikeluarkan dari queue. Queue ini sering disebut dengan list dengan dua pintu akses, yaitu pintu depan (front) dan belakang (rear atau back). Berikut adalah gambaran tentang Queue :

Struktur data queue setidaknya harus memiliki operasi-operasi sebagai berikut :

EnQueue Memasukkan data ke dalam antrian DeQueue Mengeluarkan data terdepan dari antrian IsEmpty Memeriksa apakah antrian kosong IsFull Memeriksa apakah antrian penuh

Implementasi queue dalam program juga dapat digunakan dua cara, yakni dengan array dan linked list.

(20)

20 a. Implementasi Queue dengan Linear Array

Linear array adalah suatu array yang dibuat seakan-akan merupakan suatu garis lurus dengan satu pintu masuk dan satu pintu keluar. Berikut ini diberikan deklarasi kelas Queue Linear sebagai implementasi dari Queue menggunakan linear array. Dalam prakteknya, anda dapat menggantinya sesuai dengan kebutuhan Anda. Data diakses dengan field data, sedangkan indeks item pertama dan terakhir disimpan dalam field, berikut contoh program tentang queue dengan linear array.

#include<iostream> #include<stdio.h> #include<conio.h> using namespace std; const int maxq = 5; typedef struct

{ char isi[maxq+1]; int front, rear } queue;

void initqueue(queue &Q){ Q.front =1 ;Q.rear =0 ; }

void enqueue(queue &Q,char x) { if(Q.rear < maxq) {

Q.rear++;

Q.isi[Q.rear]=x ; } else cout<<"full\n"; }

void dequeue(queue &Q,char &x) { if(Q.front<=Q.rear) {

x=Q.isi[Q.front] ;

Q.front++; } else cout<<"EMPTY\n"; }

void dequeue1(queue &Q,char &x) { if(Q.rear>0) { x=Q.isi[1] ; Q.rear--; for(int i=1;i<=Q.rear;i++) Q.isi[i]=Q.isi[i+1]; } } void PrintQueue(queue Q) { if(Q.front<=Q.rear) {

for(int i=Q.front;i<=Q.rear;i++) cout<<Q.isi[i]<<" "; cout<<endl;

} }

(21)

21 main(){

queue Q; int i,n; char x;

cout<<"banyak data : ";cin>>n; initqueue(Q); for (i=1;i<=n;i++) { x=(65+rand()%26); enqueue(Q,x); } cout<<endl; cetakqueue(Q); dequeue(Q1,x); x='X'; enqueue(Q,x); }

Pada program di atas, terdapat kelemehan yaitu queue mudah penuh, untuk itu dequeue diganti dengan dequeue1, yaitu dengan menggeser array, hal ini kurang efisien karena menggeser elemen array memerlukan waktu, sehingga yang paling efisien adalah implementasi queue dengan Circular array.

b. Implementasi Queue dengan Circular Array

Circular array adalah suatu array yang dibuat seakan-akan merupakan sebuah lingkaran dengan titik awal (front) dan titik akhir (rear) saling bersebelahan jika array tersebut masih kosong.

Berikut contoh program tentang queue dengan Circular array. #include<iostream>

#include<conio.h> using namespace std; const int maxq = 5; struct queue

{ char isi[maxq]; int front,rear; } ;

void initqueue(queue &Q)

{ Q.front =0 ;Q.rear =-1; for(int i=0;i<maxq;i++) Q.isi[i]=48;} void enqueue(queue &Q,char x)

{ if((Q.isi[(Q.rear+1)%maxq])==48) {

Q.rear++; Q.rear=Q.rear % maxq;Q.isi[Q.rear ]=x ;}} void dequeue(queue &Q,char &x)

{ if(Q.isi[Q.front]!=48){

Q.front=Q.front % maxq; x=Q.isi[Q.front] ; Q.isi[Q.front]=48;Q.front=(Q.front++)%maxq;}}

(22)

22

main() {

queue Q;int i,n;

char x,y[5]={'U','J','I','A','N'}; initqueue(Q);

for (i=0;i<5;i++) enqueue(Q,y[i]);

dequeue(Q,x);dequeue(Q,x); x='B';enqueue(Q,x); x='D'; enqueue(Q,x); dequeue(Q,x);dequeue(Q,x); x='C';enqueue(Q,x); x='E'; enqueue(Q,x); for (i=0;i<5;i++) cout<<Q.isi[i]<<" ";

}

c. Queue menggunakan Linked List

Selain implementasi queue dengan array seperti telah dijelasnkan sebelumnya, ada cara lain untuk mengimplementasi queue yakni dengan linked list. Keunggulannya dibandingkan array tentu saja adalah penggunaan alokasi memori yang dinamis sehingga menghindari pemborosan memori. Berikut adalah contoh program tentang queue dengan menggunakan linked list.

#include<iostream> #include<conio.h> #include<string.h> using namespace std; typedef struct node { char data;

struct node *next; } *tipequeue; typedef struct

{ tipequeue front,rear; } queue;

void initqueue(queue &Q)

{ Q.front = NULL; Q.rear=NULL; }

void enqueue(queue &Q,char x) { tipequeue b;

b=new node; b->next=NULL; b->data=x;

if (Q.rear==NULL) {Q.front=b;Q.rear=b;} else { Q.rear->next=b; Q.rear = b;} }

void dequeue(queue &Q,char &x) {tipequeue t;

if (Q.front!=NULL) { x=Q.front->data; t=Q.front; Q.front=t->next; delete t; if(Q.front==NULL) Q.rear=NULL; } else cout<<"Empty\n"; }

void PrintQueue(queue Q) { tipequeue t;

(23)

23 if (Q.front!=NULL) { t=Q.front; while(t!=NULL) { cout<<t->data<<" "; t=t->next; } cout<<endl; } }

void buatdata(char x[1000],int &n) { cout<<"banyak data : ";cin>>n; for(int i=1;i<=n;i++){ x[i]=65+rand()%26; cout<<x[i]<<" "; } cout<<endl; }

void BucketSort(char x[1000],int n) { queue AQ[26];char k;int i;

for(k='A';k<='Z';k++) initqueue(AQ[k-65]); for(i=1;i<=n;i++) enqueue(AQ[x[i]-65],x[i]); i=1; for(k='A';k<='Z';k++){ while (AQ[k-65].front!=NULL){ dequeue(AQ[k-65],x[i]); i++; } }

for(int i=1;i<= n;i++) cout<<x[i]<<" "; } main() { char x[1000]; int n; buatdata(x,n); BucketSort(x,n); }

2.5 Latihan Soal

1. Sebutkan apa saja keuntungannya membuat struktur data dengan tipe data array dan keuntungannya membuat struktur data dengan tipe data pointer, kemudian mengapa implementasi queue dengan array ada sedikit masalah sehingga harus menggunakan array melingkar.

(24)

24 2. Dengan menggunakan stack buatlah subprogram untuk melakukan konversi notasi infix ke

notasi postfix, sebagai gambaran :

Input berupa ekspresi aritmatika dalam notasi infix sebagai berikut :

((A * B) + C / D – E^F) * G ( dengan prioritas operasi : ^ , * atau / , + atau - ) Output yg dihasilkan ekspresi aritmatika dalam notasi postfix:

AB*CD/+EF^–G*

(Saudara boleh langsung menggunakan subprogram standar pada stack)

3. Berikut adalah subprogram untuk menghapus node-node dimulai dari node dengan data = x hingga node terakhir pada doubly linked list, lengkapilah subprogram tersebut dengan mengisi statemen/variable yang sesuai pada ...

void DeleteNode(Dlist &L) { int x;

Dlist t,r;

cout<<"data awal yg mau dihapus :";cin>>x; if ( L->data == x ) {

while ( L != NULL ) {

r = L ; L = L->next ; delete r ; } } else {

t = L;

while ( t != NULL && t->data != x ) t = t->next ; if ( t == NULL) cout<<" data tidak ada"<<endl; else { t->prev->next = NULL; while ( t != NULL ) { r = t ; t = t->next ; delete r ; } } } }

4. Dengan menggunakan stack buatlah subprogram untuk membalik urutan elemen matrik, sebagai gambaran berikut contoh matrik input dan outputnya.

Input : 7 5 2 1 7 3 Output : 2 8 9 4 3 5 3 7 4 8 7 2 2 7 8 4 7 3 5 3 4 9 8 2 3 7 1 2 5 7

(25)

25

BAB III

STRUKTUR DATA NON LINEAR

3.1 Pendahuluan

Deskripsi singkat : Bab ini menjelaskan tentang struktur data non linear yang meliputi: matriks, multiple linked list, tree (BST dan AVL Tree) dan graf.

Manfaat : Mahasiswa memahami tentang berbagai macam struktur data non linear dan dapat mengimplementasikan pada beberapa permasalahan yang sesuai.

Relevansi : Struktur data non linear banyak digunakan dalam menyelesaikan masalah pemrograman yang lebih kompleks dan akan merupakan dasar dari struktur data lanjut.

Learning Outcomes : Mahasiswa Dapat menganalisis, merancang dan meng-implementasikan struktur data non linear seperti matriks, multiple linked list, tree dan graf.

Alokasi dan waktu : Bahan yang ada pada bab ini membutuhkan alokasi waktu kurang lebih 450 menit, dan disampaikan pada minggu keenam sampai minggu kedelapan perkuliahan.

Definisi : Struktur data non linear adalah struktur data yang tidak linear, yaitu antara lain yang akan dibahas dalam bab ini adalah matriks, menggunakan array 2 dimensi, multiple linked list dan struktur data Tree atau pohon terutama pohon biner.

3.2 Matriks, Array Dua Dimensi

Array dua dimensi sering digambarkan sebagai sebuah matriks, merupakan perluasan dari array satu dimensi. Jika array satu dimensi hanya terdiri dari sebuah baris dan beberapa kolom elemen, maka array dua dimensi terdiri dari beberapa baris dan beberapa kolom elemen yang bertipe sama sehingga dapat digambarkan sebagai berikut:

0 1 2 3 4 5 6

0 10 21 23 43 45 78 65

1 45 43 65 12 21 12 21

2 32 34 23 56 54 34 45

(26)

26 Bentuk umum:

<tipe data> NamaArray [m][n];

Atau

<tipe data> NamaArray [m][n] = { {a,b,..z},{1,2,...,n-1} };

Contoh:

double matrix[4][7];

Pendeklarasian array dua dimensi hampir sama dengan pendeklarasian array satu dimensi, kecuali bahwa array dua dimensi terdapat dua jumlah elemen yang terdapat di dalam kurung siku dan keduanya boleh tidak sama.

Elemen array dua dimensi diakses dengan menuliskan kedua indeks elemennya dalam kurung siku seperti pada contoh berikut:

matrix[1][2] = 65; matrix[3][6] = 45;

Berikut contoh program tentang penggunaan array 2 dimensi. #include<iostream>

#include<conio.h> #include<stdio.h> using namespace std;

int cost[10][10],dist[20],i,j,n,k,m,S[20],v,totcost,path[20],p;

int shortest(int v,int n) {int min; for(i=1;i<=n;i++) { S[i]=0; dist[i]=cost[v][i]; } path[++p]=v; S[v]=1; dist[v]=0; for(i=2;i<=n-1;i++) { k=-1; min=9999;

(27)

27 for(j=1;j<=n;j++) { if(dist[j]<min && S[j]!=1) { min=dist[j]; k=j; } } if(cost[v][k]<=dist[k]) p=1; path[++p]=k; for(j=1;j<=p;j++) cout<<path[j]<<" "; // cout <<"\n"; // cout <<k; S[k]=1; for(j=1;j<=n;j++)

if(cost[k][j]!=9999 && dist[j]>=dist[k]+cost[k][j] && S[j]!=1) dist[j]=dist[k]+cost[k][j]; cout<<dist[j]<<endl; } } main() { int c;

cout <<"enter no of vertices :"; cin >> n;

cout <<"enter no of edges :"; cin >>m;

cout <<"\nenter\nEDGE Cost\n"; for(k=1;k<=m;k++) { cin >> i >> j >>c; cost[i][j]=c; } for(i=1;i<=n;i++) for(j=1;j<=n;j++)

if(cost[i][j]==0 && i!=j) cost[i][j]=9999; cout <<"enter initial vertex :";

cin >>v;

cout << v<<"\n"; shortest(v,n); getch(); }

(28)

28

3.3 Multipe Linked list

Multiple linked list adalah linked list dengan linked field lebih dari satu dan bentuknya tidak linear. Sebagai ilustrasi dari multiple linked list dapat dilihat pada gambar berikut.

Berikut contoh program tentang multiple linked list, yaitu untuk menyimpan data peserta pelatihan dimana banyak pelatihan dan pesertanya bisa dinamis.

#include<iostream> #include<conio.h> using namespace std;

typedef struct nodep { char nama[20]; struct nodep *next; } *peserta;

typedef struct node

{ char pelatihan[20]; struct node *next; peserta down; } *list;

list L;

void InsertPelatihan(list &l) {

int i,n; list b;

cout<<"banyak pelatihan : ";cin>>n; for (i=1;i<=n;i++){

b=new node;

b->next=NULL;b->down=NULL;

cout<<"Nama Pelatihan : ";cin>>b->pelatihan; if (l==NULL) l=b;

else {b->next=l; l=b;}

} }

(29)

29 void cetakdata(list l) {list p;peserta q; if (l!=NULL) { p=l;cout<<endl; while (p!=NULL) { cout<<p->pelatihan<<" : "; q=p->down; while (q!=NULL) { cout<<q->nama<<", ";q=q->next;} p=p->next;cout<<endl; } } else cout<<"kosong"; }

void InsertPeserta(list &l) {

int i,n;char namapelatihan[20]; list p;peserta b;

cout<<"Insert Peserta "<<endl;

cout<<"Nama pelatihan: ";cin>>namapelatihan; p=l;

while (p!=NULL && strcmp(p->pelatihan,namapelatihan)!=0) p=p->next; if (p==NULL) cout<<"nama pelatihan belum ada\n"; else

if(strcmp(p->pelatihan,namapelatihan)==0) { cout<<"banyak peserta : ";cin>>n;

for (i=1;i<=n;i++){

b=new nodep; b->next=NULL;

cout<<"Nama peserta : ";cin>>b->nama; if (p->down==NULL) p->down=b; else {b->next=p->down; p->down=b; } } } }

void HapusPeserta(list &l) {

char namapelatihan[20],namapeserta[20]; list p;peserta b,c;

cout<<"Hapus Peserta "<<endl;

cout<<"Nama pelatihan: ";cin>>namapelatihan; p=l;

while (p!=NULL && strcmp(p->pelatihan,namapelatihan)!=0) p=p->next; if (p==NULL) cout<<"nama pelatihan tidak ada\n";

(30)

30 else if(strcmp(p->pelatihan,namapelatihan)==0) {

b=p->down;

if(b==NULL)cout<<"tidak ada pesertanya"; else{

cout<<"masukkan nama peserta: "; cin>>namapeserta;

if (strcmp(b->nama,namapeserta)==0) {c=p->down;p->down=c->next;free(c);} else {

while(b->next!=NULL&&strcmp(b->next->nama,namapeserta)!=0) b=b->next; if (b->next==NULL) cout<<"peserta tidak ada";

else if(strcmp(b->next->nama,namapeserta)==0){ c=b->next;b->next=c->next;free(c); } } } } } main() { int x; L=NULL; InsertPelatihan(L); InsertPeserta(L); cetakdata(L); HapusPeserta(L); cetakdata(L); HapusPeserta(L); cetakdata(L); getch(); }

3.4 Struktur Data Tree

Struktur data Tree atau pohon adalah struktur data yang tidak linear dan berbentuk herarki, atau dapat didefinisikan sebagai kumpulan node atau simpul (mulai pada simpul akar), di mana setiap node adalah struktur data yang terdiri dari nilai, bersama dengan daftar referensi ke node anak-anaknya atau cabang-cabangnya.

(31)

31 Sebagai tipe data, pohon memiliki nilai dan anak-anak, dan anak-anak itu sendiri bisa berupa pohon, nilai dan anak-anak dari pohon diinterpretasikan sebagai nilai dari simpul akar dan subpohon anak-anak dari simpul akar. dalam hal ini daftar anak-anak dapat menjadi ukuran tetap (percabangan faktor, terutama 2 atau "biner"), jika diinginkan.

Sebagai struktur data, pohon adalah sekelompok node, dimana setiap node memiliki nilai dan daftar referensi ke node lain (anak-anaknya). Struktur data Tree yang akan dibahas adalah struktur data binary tree (pohon biner).

Pohon biner merupakan pohon yang memiliki ketentuan setiap node hanya boleh memiliki maksimal dua subtree dan kedua subtree tersebut harus terpisah. Sesuai dengan definisi tersebut, maka tiap node dalam binary tree hanya boleh memiliki paling banyak dua anak.

Berikut ini adalah ilustrasi pohon biner :

Implementasi Tree dalam program, ada beberapa hal yang perlu diperhatikan yaitu :

1. deklarasi pohon 2. membuat pohon

3. memeriksa apakah pohon kosong 4. membuat node baru

5. menambah node ke pohon 6. membaca sebuah node

(32)

32 7. mengunjungi pohon secara In Order

(Kunjungi Left Child, cetak isi node yang dikunjungi, kunjungi Right Child) 8. mengunjungi pohon secara Pre Order

(Cetak isi node yang dikunjungi, kunjung Left Child, kunjungi Right Child) 9. mengunjungi pohon secara Post Order

(Kunjungi Lift Child, kunjungi Right Child, cetak node yang dikunjungi) 10. mencari node tertentu dalam pohon

Berikut contoh implementasi program tentang Pohon Biner. #include<iostream>

#include<stdio.h> #include<conio.h> using namespace std;

typedef struct node { char data;

struct node *kanan,*kiri; } simpul;

typedef simpul *tree; tree T;

void BST(tree *T,char x) { tree b;

if (*T==NULL) { b=new simpul;

b->data=x;b->kanan=NULL;b->kiri=NULL; *T=b;}

else if(x<(*T)->data) BST(&(*T)->kiri,x); else BST(&(*T)->kanan,x); } void PRE(tree T) { if (T!=NULL) { cout<<T->data<<" "; PRE(T->kiri); PRE(T->kanan); } }

(33)

33 void IN(tree T) { if (T!=NULL) { IN(T->kiri); cout<<T->data<<" "; IN(T->kanan); } } void POST(tree T) { if (T!=NULL) { POST(T->kiri); POST(T->kanan); cout<<T->data<<" "; } } main (){

tree P;char x;int i,n; P=NULL;

cout<<"banyak data : ";cin>>n; for (i=1;i<=n;i++) {

x=(65+rand()%26); cout<<x<<" "; BST(&P,x);

}

cout<<"pre : "; PRE(P); cout<<endl; cout<<"In : "; IN(P); cout<<endl; cout<<"post : "; POST(P);

getch(); }

Sebuah binary search tree (BST) adalah sebuah pohon biner yang boleh kosong, dan setiap nodenya harus memiliki identifier/value. value pada semua node subpohon sebelah kiri adalah selalu lebih kecil dari value dari root, sedangkan value subpohon di sebelah kanan adalah sama atau lebih besar dari value pada root, masing – masing subpohon tersebut (kiri&kanan) itu sendiri adalah juga BST. Sebagai gambaran berikut adalah sebuah BST.

(34)

34 Operasi penambahan node/insert pada BST :

BST sebelum dilakukan Insert BST setelah dilakukan Insert node 120

Sebuah BST, pada dasarnya adalah sebuah pohon biner (binary tree), oleh karena itu, kita dapat melakukan traversal pada setiap node dengan metode inorder, preorder maupun postorder. dan jika kita melakukan traversal dengan metode inorder, pada dasarnya kita telah melakukan traversal valuenya secara terurut dari kecil ke besar, jadi ini sebagai sorting algoritma.

Struktur data BST sangat penting dalam struktur pencarian, misalkan, dalam kasus pencarian dalam sebuah larik, jika larik sudah dalam keadaan terurut maka proses pencarian akan sangat cepat, jika kita menggunanan pencarian biner. Akan tetapi, jika kita ingin melakukan perubahan isi larik (insert atau delete), menggunakan larik/array akan sangat lambat, karena proses insert dan delete dalam larik butuh memindahkan banyak elemen setiap saat. Sebaliknya binary tree memberikan jawaban sempurna atas semua permasalahan ini, dengan memanfaatkan binary tree kita dapat melakukan pencarian elemen/node value dalam kompleksitas algorimta O(n log n) langkah saja.

Kebanyakan aplikasi saat ini melakukan operasi penambahan dan penghapusan elemen secara terus-menerus tanpa urutan yang jelas urutannya. Oleh karena itu sangatlah penting untuk mengoptimasi waktu pencarian dengan menjaga agar pohon tersebut mendekati seimbang/balance sepanjang waktu. Dan hal ini telah diwujudkan oleh 2 orang matematikawan Russia , G.M. Adel’son-Vel’skii dan E.M. Landis. Oleh karena itu Binary

(35)

35 tersebut. Tujuan utama dari pembuatan AVL-Tree ini adalah agar operasi pencarian, penambahan, dan penghapusan elemen dapat dilakukan dalam waktu O(log n) bahkan untuk kasus terburuk pun. Tidak seperti Binary Search Tree biasa yang dapat mencapai waktu O(1.44 log n) untuk kasus terburuk.

Dalam pohon yang benar-benar seimbang, subpohon kiri dan kanan dari setiap node mempunyai tinggi yang sama. Walaupun kita tidak dapat mencapai tujuan ini secara sempurna, setidaknya dengan membangun Binary Search Tree dengan metode penambahan elemen yang nantinya akan kita bahas, kita dapat meyakinkan bahwa setiap subpohon kiri dan kanan tidak akan pernah berselisih lebih dari 1. Jadi, sebuah AVL-Tree merupakan Binary

Search Tree yang subpohon kiri dan kanan dari akarnya tidak akan berselisih lebih dari 1 dan

setiap subpohon dari AVL-Tree juga merupakan AVL-Tree. Dan setiap simpul di AVL-Tree mempunyai faktor penyeimbang (balance factor) yang bernilai left-higher (subpohon kiri > kanan), equal-height (subpohon kiri = kanan), righthigher (subpohon kiri < kanan).

Proses balancing pada AVL-Tree dilakukan dengan cara :

Single Rotation (kiri dan kanan)

Double Rotation (kiri dan kanan)

Berikut contoh kedua proses tersebut :

(36)

36

BST sebelum dilakukan insert 95 BST setelah insert 95 dan double rotation kanan

Aplikasi dari struktur data pohon, antara lain yaitu untuk kompresi data string menggunakan huffman tree yaitu pohon biner yang disusun berdasarkan frekuensi kemunculan huruf pada string, aplikasi yang lain adalah konversi dari notasi infix ke notasi prefix atau postfix dan aplikasi pada pengurutan data dengan algoritma heapsort yang akan dibahas pada Bab IV.

3.5 Struktur Data Graf

Graf banyak digunakan untuk merepresentasikan suatu permasalahan, sehingga perlu dibahas bagaimana menyimpan graf di RAM, yaitu struktur data graf. Graf adalah kumpulan dari simpul atau vertex dan busur atau edge yang secara matematis dinyatakan sebagai :

G = (V, E) Dimana

G = Graph

V = Simpul, atau Vertex, atau Node, atau Titik E = Busur, atau garis, atau Edge, atau arc Contoh graf :

(37)

37

Graph Berarah dan Graph Tak Berarah :

B A C D E B A C D E

Directed graph Undirected graph

e1 e3 e4 e7 e5 e2 e6 v1 v2 v4 v5 v3 v1 v2 v3 v5 v4 e1 e2 e3 e4 e5 e6 e7 e8 e9 e10

Dapat dilihat dari bentuk busur yang artinya urutan penyebutan pasangan 2 simpul.

Graph tak berarah (undirected graph atau non-directed graph) :

• Urutan simpul dalam sebuah busur tidak dipentingkan. Mis busur e1 dapat disebut busur AB atau BA

Graph berarah (directed graph) :

• Urutan simpul mempunyai arti. Mis busur AB adalah e1 sedangkan busur BA adalah e8.

Graph Berbobot (Weighted Graph)

• Jika setiap busur mempunyai nilai yang menyatakan hubungan antara 2 buah simpul, maka busur tersebut dinyatakan memiliki bobot.

• Bobot sebuah busur dapat menyatakan panjang sebuah jalan dari 2 buah titik, jumlah rata-rata kendaraan perhari yang melalui sebuah jalan, dll.

Graph Berbobot : B A C D E B A C D E

Directed graph Undirected graph

5 3 12 6 8 4 3 v1 v2 v4 v5 v3 v1 v2 v3 v5 v4 5 e2 3 12 8 3 6 4 7 10

Panjang busur (atau bobot) mungkin tidak digambarkan secara panjang yang proposional dengan bobotnya. Misal bobot 5 digambarkan lebih panjang dari 7.

(38)

38

Representasi Graph dalam bentuk

matrix

• Adjacency Matrix Graph tak berarah

0 1 0 1 0

1 0 1 0 1

0 1 0 1 1

1 0 1 0 1

0 1 1 1 0

B A C D E Graph A B A 0 B C 1 2 3 4 C D E D E 0 1 2 4 3 Urut abjad Degree simpul : 3

Representasi Graph dalam bentuk

matrix

• Adjacency Matrix Graph berarah

0 1 0 1 0

1 0 1 0 1

0 1 0 1 1

0 0 1 0 1

0 0 0 0 0

Graph A B A 0 B C 1 2 3 4 C D E D E 0 1 2 4 3 B A C D E ke dari out in

(39)

39

Graph berarah dan berbobot

B A C D E 5 3 2 14 12 6 7 12

0 5 0 2 0

6 0 3 0 0

0 0 0 0 9

0 0 12 0 7

0 14 0 0 0

A A 0 B C 1 2 3 4 D E 0 1 2 4 3 B C D E

Perhatikan pemilihan nilai 0.

Representasi Graph dalam bentuk

Linked List

• Adjency List graph tak berarah

• Digambarkan sebagai sebuah simpul yang

memiliki 2 pointer.

• Simpul vertex :

Simpul edge :

info info

Menunjuk ke simpul vertex berikutnya, dalam untaian simpul

yang ada.

Menunjuk ke simpul

edge pertama Menunjuk ke simpul edge berikutnya, bila

masih ada. Menunjuk ke simpul

vertex tujuan yang berhubungan dengan

simpul vertex asal.

(40)

40 Contoh : untuk vertex A, memiliki 2 edge yang

terhubung yaitu e1 dan e2.

A C D B E e2 Graph e1 B A C D E e1 e3 e4 e7 e5 e2 e6 Urut abjad

Algoritma Minimum Spanning Tree Problem

Tree sebenarnya adalah suatu graf terhubung tanpa cycle.

Spanning tree dari suatu graf G adalah tree yang memuat semua vertek dari G. Contoh : 1 6 2 Graf G : 4 3 5 3 2 4

(41)

41 Spanning tree yang total costnya minimum (10) adalah :

1 2

3 5

3 2 4

Suatu contoh aplikasi dari masalah minimum spanning tree adalah misalkan titik dari graf G adalah kota dan cost dari suatu garis (u,v) adalah biaya pemasangan telephone line dari kota u ke v. Maka minimum spanning tree dari G adalah merepresentasikan biaya total minimal untuk memasang telephone line n kota.

Problem : Bagaimana menentukan spanning tre dari suatu graf (terhubung) yang total costnya minimum?.

Catatan : Spanning tree dari suatu graf G dengan n titik mempunyai tepat n-1 garis. Ada 2 algoritma untuk menentukan minimum spanning tree yaitu Prim dan Kruskal. Prim bekerja berdasarkan titik, Sedangkan Kruskal bekerjannya berdasar garis.

(42)

42

PRIM

Input : Graf G(V,E), V: himpunan titik dan E himpunan garis. Output: Minimum spanning tree T : himpunan garis.

(himpunan B untuk mencatat titik yang sudah didapat) Algoritma :

Begin T = {}

B = { sembarang titik dari G, misalkan titik 1 } While B  V do begin

Tentukan garis e =(u,v) dengan cost minimum dimana u B dan v V-B T = T {e}

B = B  {v} End

End

KRUSKAL

Input : Graf G(V,E), V: himpunan titik dan E himpunan garis. Output : Minimum spanning tree T : himpunan garis.

(sebagai bantuan digunakan himpunan C1,C2, …,Cn yang berisi titik)

Algoritma : Begin

SORT hinpunan E secara acending. T = {};C1 = {1}, C2 ={2}, …,Cn ={n}.

Repeat

e =(u,v) tanpa menentukan yang costnya minimum karena E sudah sorted. Cari himpunan C yang memuat u  Cu

Cari himpunan C yang memuat v  Cv If Cu  Cv then begin

Gabung Cu dan Cv menjadi satu himpunan. T = T {e}

End

Until T memuat n-1 garis End

(43)

43 Untuk lebih jelasnya diberikan contoh sebagai berikut:

Perhatikan graf G di atas :

1 6 2

Graf G :

4 3 5

3 2 4

Maka proses mendapatkan minimum spanning tree sebagai berikut :

PRIM KRUSKAL

(problem size n ) (problem size m (banyak garis))

Step (u,v) B Step e=(u,v) Himpunan C

Awal -- {1} Awal -- {1},{2},{3},{4} 1 (1,4) {1,4} 1 (3,4) {1},{2},{3,4} 2 (3,4) {1,4,3} 2 (1,4) {1,3,4},{2} 3 (2,4) {1,4,3,2} 3 (1,3) ditolak (Cu=Cv) 4 (2,4) {1,2,3,4} T={ (1,4), (3,4), (2,4) } T={ (3,4), (1,4), (2,4) }

3.6 Latihan Soal

1. Mengapa implementasi Tree dengan array kurang efisien sehingga harus menggunakan pointer, kemudian untuk menyimpan data menu (menu utama, submenu, subsubmenu) suatu aplikasi mengapa sebaiknya menggunakan multiple linked list?

2. Berikut adalah subprogram untuk melakukan find and replace dari suatu BST, dimana data x diganti dengan data y dengan syarat setelah diganti harus tetap BST, lengkapilah subprogram tersebut dengan mengisi statemen yang seharusnya pada ...

(44)

44 void FindReplace(tree &T,char x,char y)

{tree p,q;

if(T!=NULL) { q=T; p=q;

while (q!=NULL && x!=q->data) { p=q;

if (x<p->data) {q=p->kiri;} else {q=p->kanan;} }

if (x == q->data)

if (...) {q->data=y; cout<<"true";} else cout<<"false"; else cout<<"data tidak ada";

} }

3. Jika diketahui informasi sebagai berikut :

Preorder U L I K H E V O B A M T

Inorder I L H K E U B O A V T M

Gambarlah pohon biner yang memenuhi informasi di atas, kemudian tentukan hasil kunjungan postordernya

4. Buatlah AVL Tree berdasarkan urutan data berikut: 20, 85, 39, 58, 13, 95, 98, 55, 80, 69, 46, 10, 74

 Buatlah Binary Search Tree berdasarkan urutan data tersebut.

 Buatlah AVL Tree berdasarkan urutan data tersebut.

5. Pada implementasi BST dengan array satu dimensi, buatlah subprogram untuk menghapus suatu node daun tertentu x, sedemikian sehingga hasil treenya masih tetap BST. (Buat subprogram tentang multiple linkedlist atau tree atau hasing/searching)

6. Dengan menggunakan queue, buatlah subprogram untuk melakukan kunjungan secara level order pada pohon biner.

(45)

45

BAB IV

ALGORITMA SORTING

4.1 Pendahuluan

Deskripsi singkat : Bab ini menjelaskan tentang algoritma sorting yang optimal baik sorting internal maupun sorting eksternal yang meliputi: QuickSort, MergeSort, HeapSort, Hybrid Mergesort quicksort dan Multiway Mergesort.

Manfaat : Mahasiswa memahami tentang berbagai algoritma sorting yang optimal baik sorting internal (RAM) maupun sorting eksternal (File).

Relevansi : Algoritma sorting sering digunakan dalam penyelesaian masalah pemrograman dan biasanya melibatkan data yang cukup besar.

Learning Outcomes : Mahasiswa memiliki pengetahuan mengenai sorting serta dapat mengimplementasikan dalam program komputer.

Alokasi dan waktu : Bahan yang ada pada bab ini membutuhkan alokasi waktu kurang lebih 300 menit, dan disampaikan pada minggu kesembilan dan kesepuluh perkuliahan.

Pada bab ini dijelaskan beberapa algoritma pengurutan data (sorting), yaitu : Merge Sort, Quick Sort (review) dan Heap Sort. Pengurutan atau sorting merupakan proses untuk menyusun kembali kumpulan entri-entri yang telah dimasukkan dengan suatu aturan tertentu. Secara umum ada 2 macam pengurutan yaitu pengurutan secara menaik (ascenden) dan pengurutan secara menurun (descenden).

4.2 Algoritma Quick Sort dan Merge Sort

Algoritma Quick Sort dan algoritma Merge Sort dirancang dengan teknik devide and conquer, merupakan algoritma sorting yang optimal dan sangat efisien.

Quick Sort adalah algoritma yang proses pembagian data dengan cara partisi, sehingga diharapkan lebih menghemat memory. Teknik devide and conquer yang digunakan yaitu dengan mempartisi data yang disimpan di array X menjadi 2 subarray, yaitu subarray1 berisi data yang ≤ bound dan subarray2 berisi data yang ≥ bound, dimana bound (pivot) adalah suatu elemen yang diharapkan bisa membagi X menjadi 2 subarray yang banyak datanya

(46)

46 seimbang, kemudian terhadap masing-masing subarray dilakukan dengan cara yang sama secara rekursif. Algoritma QuickSort secara rekursif dapat dinyatakan sebagai berikut :

Subprogram QuickSort (X[ ], n) { If ( n>1) then { Pilih bound; Partisi (X, bound); QuickSort(subarray1, j-1); QuickSort(subarray2, j+1); } }

Sedangkan subprogram Partisi adalah sebagai berikut : Subprogram Partisi (X[ ], first, last ) {

bound = X[first]; i = first +1; j=last; while ( i<j ) { while (X[ i ] < bound ) i = i + 1; while (X[ j ] > bound ) j = j – 1; if ( i < j ) Swap(X[ i ], X[ j ]); } Swap( X[ first ], X[ j ]); }

Algoritma QuickSort mempunyai kelemahan yaitu untuk keadaan worstcase, salah satu subarray selalu kosong, kompleksitas waktunya O(n2), hal ini karena sangat sulit untuk mengontrol proses partisi. Algoritma MergeSort membagi data yang disimpan di larik X menjadi 2 subarray yang berukuran sama dan mengurutkan masing-masing subarray dengan cara rekursif kemudian melakukan merge kedua subarray yang sudah terurut tersebut.

(47)

47 Implementasi dari algoritma merge sort memakai tiga buah tabel, dua untuk menyimpan elemen dari tabel yang telah di bagi dua dan satu untuk menyimpan elemen yang telah terurut. Namun algoritma ini dapat juga dilakukan langsung pada dua tabel, sehingga menghemat ruang atau memori yang dibutuhkan.

Subprogram MergeSort secara rekursif adalah sebagai berikut : Subprogram MergeSort (X[ ], first, last) {

If ( first < last) then { mid = ( first + last ) / 2 ; MergeSort(X[ ], first, mid); MergeSort(X[ ], mid + 1, last);

Merge(X[ ], first, mid, last); }

}

Sedangkan subprogram Merge adalah sebagai berikut : Subprogram Merge (X[ ], first, mid, last ) {

I = first; j = mid + 1;k = 0; while ( i ≤ mid or j ≤ last ) {

if ( X[ i ] < X[ j ] ) {Temp[k] = X[ i ]; i = i + 1;} else {Temp[k] = X[ j ]; j = j + 1;}

}

Masukkan data yang tersisa ke dalam Temp; Copy Temp ke array X;

}

Berikut adalah program tentang Merge Sort dan Quick Sort.

#include<iostream> #include<stdlib.h> #include<conio.h> using namespace std;

typedef int larik[250001]; long long c=0;

(48)

48 int n,cc=0;

void cetakdata(larik x,int n) {int i; for (i=1;i<=n;i++) { cout<<x[i]<<" "; } cout<<endl; cout<<endl;getch(); }

void partisi(larik x,int aw,int ak,int &j) { int i,t,pivot;

pivot=x[aw]; i=aw;j=ak; while (i<j){

while ((i<ak)&&(x[i]<=pivot)) {i++;cc++;}if(i<ak) cc++; while ((j>aw)&&(x[j]>pivot)) {j--;cc++;}if(j>aw) cc++;

if (i<j) {t=x[i];x[i]=x[j];x[j]=t;} }

x[aw]=x[j];x[j]=pivot; }

void qsort(larik x,int aw,int ak) {int j; if (aw<ak) { partisi(x,aw,ak,j);//cetakdata(x,n); qsort(x,aw,j-1); qsort(x,j+1,ak); } }

void merge(larik x, int aw,int mid,int ak) {larik z;

int i,j,k,l;

i=aw; j=mid+1; k=aw; do {

if(x[i]<=x[j]) {z[k]=x[i];i++;} else {z[k]=x[j];j++;}

k++;}

while ((i<=mid) && (j<=ak));

if (i>mid) for (l=j;l<=ak;l++) {z[k]=x[l];k++;} else for (l=i;l<=mid;l++) {z[k]=x[l];k++;} for (k=aw;k<=ak;k++) x[k]=z[k];

(49)

49 void mergesort(larik x,int aw,int ak)

{int mid; if(aw<ak) { mid =(aw+ak)/2; mergesort(x,aw,mid); mergesort(x,mid+1,ak); merge(x,aw,mid,ak); } }

void buatdata(larik x,int &n) {int i;

cout<<"banyak data :";cin>>n; // srand(time(NULL)); for (i=1;i<=n;i++) { x[i]= rand()%100+1; // cout<<x[i]<<" "; } cout<<endl; // cout<<endl; } main() { int i,j; larik x; buatdata(x,n); cetakdata(x,n);

clock_t begin_time = clock(); mergesort1(x,1,n);

cout << float( clock () - begin_time )/CLOCKS_PER_SEC; cetakdata(x,n);

}

4.3 Algoritma Hybrid MergeQuick

Algoritma pengurutan internal dalam pengurutan eksternal biasanya digunakan algoritma quicksort karena algoritma quicksort untuk data dalam jumlah yang kecil lebih cepat dibanding mergesort sedangkan untuk jumlah data yang besar Mergesort lebih cepat. Pada penelitian ini dirancang algoritma hybrid yang memanfaatkan kelebihan dari algoritma mergesort dan quicksort, algoritma hybrid tersebut diberi nama MergeQuick, yang algoritmanya sebagai berikut :

(50)

50 Subprogram MergeQuick (X[ ], first, last) {

If ( last-first < 1000) then Quicksort(X[ ], first, last) else {

mid = ( first + last ) / 2 ; MergeSort(X[ ], first, mid); MergeSort(X[ ], mid + 1, last);

Merge(X[ ], first, mid, last); }

}

Dimana subprogram Quicksort dan subprogram Merge sama persis dengan yang sudah dibahas pada sebelumnya.

Berikut hasil perbandingan antara algoritma MergeQuick dengan algoritma Mergesort dan Quicksort untuk jumlah data 1 juta, 2 juta hingga 5 juta, selengkapnya dapat dilihat pada Tabel 4.1.

Tabel 4.1 Perbandingan Waktu Proses MergeQuick dengan Mergesort dan Quicksort

Banyak data

Waktu Proses (dalam detik) MergeQuick MergeSort QuickSort

N=1 juta 0,354 0,419 0,464

N=2 juta 0,743 0,88 1,346

N=3 juta 1,137 1,348 2,684

N=4 juta 1,536 1,815 4,380

(51)

51 Dari Tabel 4.1 menunjukkan bahwa algoritma MergeQuick lebih cepat dibanding dengan algoritma Mergesort dan Quicksort, sehingga pada penelitian ini akan digunakan algoritma MergeQuick untuk pengurutan internalnya.

4.4 Algoritma Heap Sort

HeapSort adalah algoritma pengurutan data berdasarkan perbandingan, dan termasuk golongan selection sort. Walaupun lebih lambat daripada quick sort pada kebanyakan mesin , tetapi heap sort mempunyai keunggulan yaitu kompleksitas algoritma pada kasus terburuk adalah n log n.

Algoritma pengurutan heap sort ini mengurutkan isi suatu larik masukan dengan memandang larik masukan sebagai suatu Complete Binary Tree (CBT).

Setelah itu Complete Binary Tree (CBT) ini dapat dikonversi menjadi suatu heap tree. Setelah itu Complete Binary Tree (CBT) diubah menjadi suatu priority queue.

Algoritma pengurutan heap dimulai dari membangun sebuah heap dari kumpulan data yang ingin diurutkan, dan kemudian menghapus data yang mempunyai nilai tertinggi dan menempatkan dalam akhir dari larik yang telah terurut.

Heap

Setelah memindahkan data dengan nilai terbesar, proses berikutnya adalah membangun ulang heap dan memindahkan nilai terbesar pada heap tersebut dan menempatkannya dalam tempat terakhir pada larik terurut yang belum diisi data lain.

(52)

52 Proses ini berulang sampai tidak ada lagi data yang tersisa dalam heap dan larik yang terurut penuh. Dalam implementasinya kita membutuhkan dua larik – satu untuk menyimpan heap dan satu lagi untuk menyimpan data yang sudah terurut.

Tetapi untuk optimasi memori, kita dapat menggunakan hanya satu larik saja. Yaitu dengan cara menukar isi akar dengan elemen terakhir dalam heap tree. Jika memori tidak menjadi masalah maka dapat tetap menggunakan dua larik yaitu larik masukan dan larik hasil.

Heap Sort memasukkan data masukan ke dalam struktur data heap.

Nilai terbesar (dalam max-heap) atau nilai terkecil (dalam min-heap) diambil satu per satu sampai habis, nilai tersebut diambil dalam urutan yang terurut.

Algoritma untuk heap sort : function heapSort(a, count)

input: sebuah larik tidak terurut a dengan panjang length (pertama letakkan a dalam max-heap) heapify(a, count) end = count -1 while end > 0 { remove ( ) reheapify ( ) end = end – 1 } Algoritma Heapify

Algoritma Heapify adalah membangun sebuah heap dari bawah ke atas, secara berturut-turut berubah ke bawah untuk membangun heap. Permasalahan pertama yang harus kita pertimbangkan dalam melakukan operasi heapify adalah dari bagian mana kita harus memulai. Bila kita mencoba operasi heapify dari akar maka akan terjadi operasi runut-naik seperti algoritma bubble sort yang akan menyebabkan kompleksitas waktu yang ada akan berlipat ganda. Sebuah versi lain adalah membangun heap secara atas-bawah dan berganti-ganti ke atas untuk secara konseptual lebih sederhana untuk ditangani. Versi ini mulai dengan sebuah heap kosong dan secara berturut-turut memasukkan data.

Gambar

Gambar 5.1  Struktur Data untuk Tabel Hash

Referensi

Dokumen terkait

Jika tidak dinyatakan demikian, variabel tersebut akan dipandang sebagai signed char sebagai bentuk default untuk jenis data char, sehingga hanya dapat menampung setengah

Sebuah karya yang mirip dan dibuat untuk pemain (biasanya dua biola dan satu cello) disebut trio sonata.. Sebuah sonata untuk biola, biola alto, atau cello, secara tidak langsung

Contoh dari operasi ouput yaitu menampilkan kalimat ke layar, biasanya dilakukan untuk menampilkan perintah untuk memasukkan input ke program, atau menampilkan nilai dari suatu

Kompiler (compiler), merupakan program yang menerjemahkan program yang ditulis di dalam bahasa pemrograman tingkat tinggi me suatu himpunan instruksi mesin spesifik yang

Supaya bisa dibedakan antara laporan keuangan internal (periode pertama hingga bulan ke duabelas), maka dibuatkan satu periode khusus untuk mencatat penyesuaian

Menambah ekor pada senarai akan melibatkan penempatan node terakhir, dan kemudian merubahnya .next field dari NULL untuk menunjuk node baru seperti variabel tail dalam contoh

Layanan bimbingan karier dalam bimbingan dan konseling (BK) merupakan layanan yang dapat membantu siswa dalam rangka merencanakan karier serta mengambil keputusan sesuai diri sendiri. Perencanaan karier siswa Sekolah Menengah Pertama (SMP) berfungsi untuk pepetaan siswa ke dalam sekolah yang terkait dengan peluang masa depan individu. Penelitian ini menggunakan metode kausal komparatif,. Pengumpulan data menggunakan angket, digunakan dengan beberapa indikator yang berhubungan langsung dengan variable layanan bimbingan karier menggunakan angket dari Tohirin (2013)) dan variable perencanaan karier menggunakan teori dari Winkel dan Sri Hastuti (2005). Hasil menunjukkan adanya pengaruh dari layanan bimbingan karier terhadap perencanaan karier siswa kelas VIII SMP N 8 Sungai Lilin dengan nilai koefisien korelasi sebesar 0,496. Nilai ini berarti memiliki hubungan yang tinggi. Selanjutnya dilakukan analisis regresi untuk melihat pengaruh antara layanan bimbingan karier dengan perencanaan karier siswa dan di dapatkan koefisien regresi (x) sebesar 0,414. Nilai ini berarti bahwa setiap penambahan 1% nilai kemampuan menggunakan F-learn maka nilai motivasi belajar mahasiswa bertambah 0,414. Kemudian diperoleh nilai Sig. 0,006, karena sig. 0,006 < 0.050, maka variabel layanan bimbingan karier berpengaruh secara signifikan terhadao variabel perencanaan karier siswa. Nilai RSquare sebesar 0,587 yang artinya besaran sumbangan variabel Layanan BK terhadap variabel Perencanaan Karir Siswa sebesar 58,7%, sisanya (41,3%) berasal dari variabel lain.