· EEM227

EEM227 Veri Yapıları: Bağlı Listeye Sıralı Ekleme ve Bağlı Liste ile Kuyruk (Hafta 12)

EEM227 – Veri Yapıları · 13.12.2007 · 16.10.2026

Bu yazı, Başkent Üniversitesi EEM227 Veri Yapıları dersinin 2007 güz dönemi 12. hafta klasöründeki iki C++ programını içeriyor: tek yönlü bağlı listeye sıralı ekleme (Soru 5) ve bağlı liste kullanarak kuyruk (queue) yapısı oluşturma. Kaynak dosyalar yazının sonunda ZIP olarak indirilebilir.

Soru 5: sıralı ekleme

int x[10]={89,17,88,45,26,30,4,25,72,1}; küçükten büyüğe doğru sıralı ekleme!

Dosyanın başında, bu on sayı sırayla girildiğinde listenin her adımda aldığı hâl verilmiş:

89->NULL
17->89->NULL
17->88->89->NULL
17->45->88->89->NULL
17->26->45->88->89->NULL
17->26->30->45->88->89->NULL
4->17->26->30->45->88->89->NULL
4->17->25->26->30->45->88->89->NULL
4->17->25->26->30->45->72->88->89->NULL
1->4->17->25->26->30->45->72->88->89->NULL
Press any key to continue . . .

LLSiraliEkle fonksiyonu dört durumu ayırıyor:

  • Liste boşsa ilk düğüm head'e yerleştirilir.
  • Yeni değer head'deki değerden küçük ya da eşitse başa (sola) eklenir.
  • Liste dolaşılarak yeni değerden büyük ilk düğüm aranır; listenin sonuna gelinmiş ve son değer de küçük ya da eşitse sona eklenir.
  • Aksi hâlde yeni düğüm, önceki düğüm (pre) ile bulunan düğüm (curr) arasına eklenir.

ListedenSil ise silinecek değeri arayıp, head'de ise head'i bir ileri kaydırarak, başka bir yerdeyse önceki düğümü sonrakine bağlayarak düğümü siliyor. Fonksiyonlar head işaretçisini değiştirebilmek için onu referans olarak (node<T> * &ptr) alıyor.

#include<iostream>
#include<ctime>
using namespace std;

template <typename T>
class node
{
private:
      T nodeValue;      // data held by the node
      node<T> *next;    // next node in the list
public:

 node(const T& item, node<T> *nextNode=NULL)
      {
         nodeValue=item;
		 next=nextNode;
	  }

static T LLSiraliEkle(T value,node<T> * &ptr)
{

node<T> *curr=ptr,*pre=ptr,*s;

 if( ptr == NULL) // Liste boş ise ilk nodu heade yerleştir.
      {
       ptr = new node<T> (value);
       ptr->next = NULL;
      }

 else if (ptr->nodeValue >= value) // Başa ekle (sola)
     {
       s = new node<T> (value);
       s->next = ptr;
       ptr = s;
     }

else
 {
  while (curr->nodeValue <= value && curr->next!=NULL)
    {
      pre = curr;
      curr = curr->next;
     }

   if(curr->next == NULL && curr->nodeValue <= value) // sona ekle
       {
         s = new node<T> (value);
         s->next = NULL;
         curr->next = s;
       }

   else  // araya ekle
         {
          s = new node<T> (value);
          pre->next = s;
          s->next = curr;
         }

 } // ELSE
}

static T printList(node<T> *ptr)
      {

        while (ptr->next != NULL) // Araya ok koymak için bu şekilde yaptık...
        {
         cout << ptr->nodeValue<<"->" ;
         ptr = ptr->next;
        }
         cout<<ptr->nodeValue<<"->NULL" ;
           cout << endl;
       }

static T node<T>::ListedenSil(node<T>* &ptr, T deger)
  {
  node<T> * curr, * pre;
   pre = curr = ptr;

    while(curr->nodeValue != deger && curr->next!=NULL)
     {
        pre = curr;
       curr = curr->next;
     }

   if(curr == ptr) // Silinecek değer head de bulunduysa
   {
    ptr = ptr -> next; // head i ötele
    delete curr;
   }

   else if(curr->nodeValue == deger) // head dışında bir yerde ise
    {  pre->next = curr->next;
       delete curr;
       cout<<"Silme islemi basarili"<<endl;
    }
    else
       cout<<"Silinecek deger listede bulunamadi"<<endl;
  }

};

int main()
{
//  int x[]={89,17,88,45,26,30,4,25,72,1};
  int SilinecekDeger;
  int adet,deger;

 node<int> *head=NULL;

 srand(time(NULL));
 cout<<"Kac eleman listeye eklenecek ? ";
 cin>>adet;

 for(int i=0; i<adet; i++)
 {
    cout<<"Listeye eklenecek degeri giriniz: ";
    cin>>deger;
    node<int>::LLSiraliEkle(deger,head);
    node<int>::printList(head);
 }

 cout<<"\n Silinecek Degeri Giriniz : ";
 cin>>SilinecekDeger;

 if( node<int>::ListedenSil(head,SilinecekDeger) )
     node<int>::printList(head);
 else
    cout<<" Silinecek deger listede bulunamadı !\n";

  system("pause");
  return 0;
}

Not: ListedenSil, LLSiraliEkle ve printList T döndüreceklerini bildirdikleri hâlde return içermiyor; main'de if( node<int>::ListedenSil(...) ) ile kullanılan dönüş değeri bu yüzden tanımsız (silme sonrası liste yazdırılıp yazdırılmayacağı rastlantıya kalır). Silme başarılıysa true, değilse false döndüren bir bool fonksiyon olmalı. Ayrıca sınıf gövdesi içinde static T node<T>::ListedenSil yazımındaki node<T>:: niteleyicisi fazladır; güncel derleyiciler bunu hata sayar. Listede tek eleman varken o eleman silinirse head NULL olur ve ardından çağrılan printList boş listede çöker.

Soru: bağlı liste ile kuyruk

LL veri yapısı kullanarak, queue veri yapısı oluşturun.

Çözüm, kuyruğun önünü (qfront) ve arkasını (qback) gösteren iki işaretçi ile eleman sayısını (qsize) tutan bir linkedQueue şablon sınıfı. push yeni düğümü listenin sonuna bağlayıp qback'i güncelliyor; pop baştaki düğümü silip qfront'u bir ileri alıyor. Kopyalama kurucusu, atama operatörü ve yıkıcı, yardımcı copy() ve clear() fonksiyonlarıyla yazılmış. Sınıftaki İngilizce yorumlar, dersin kaynak kitabındaki bağlı liste kuyruk sınıfının yorumları; hata durumlarında istisna (exception) fırlatmak yerine ekrana mesaj yazdırılacak şekilde uyarlanmış.

#include <iostream>

using namespace std;

template <typename T>
class node
{
   public:
      T nodeValue;      // data held by the node
      node<T> *next;    // next node in the list

      // default constructor with no initial value
      node() : next(NULL)
      {}

      // constructor. initialize nodeValue and next
      node(const T& item, node<T> *nextNode = NULL) :
			  nodeValue(item), next(nextNode)
      {}
};

template <typename T>
class linkedQueue
{
    public:
		linkedQueue();
			// Constructor: creates an empty queue.
			// Postcondition: qsize = 0, qfront = qback = NULL

		linkedQueue(const linkedQueue<T>& obj);
			// copy constructor. builds a copy of obj

		~linkedQueue();
			// destructor. clear the linked list

		linkedQueue<T>& operator= (const linkedQueue<T>& rhs);

		void push(const T& item);
			// insert an element at the rear of the queue
			// Postcondition: the queue has one more element

		void pop();
			// remove an element from the front of the queue.
			// Precondition: the queue is not empty. if the queue
			// is empty, throw an underflowError exception
			// Postcondition: the queue has one less element

		T& front();
			// return a reference to the front of the queue.
			// Precondition: the queue is not empty. if the queue
			// is empty, throw an underflowError exception
		const T& front() const;
			// constant version

      int size() const;
			// return the current size of the queue

		bool empty() const;
			// return true if the queue is empty; otherwise return false

    private:
		node<T> *qfront, *qback;
			// the linked list with qfront stores the elements.
			// qback points to the rear of the queue
		int qsize;
			// number of elements in the queue

		void copy(const linkedQueue<T>& q);
			// copy q so the current list is identical to q

		void clear();
			// clear the list. used by the destructor and assignment

		node<T> *getNode(const T& item);
			// allocate a node with value item and pointer value NULL
			// and return a pointer to it. if memory allocation fails,
			// throw the memoryAllocationError exception
};

template <typename T>
void linkedQueue<T>::copy(const linkedQueue<T>& q)
{
	// qback moves through the list we are building and
	// winds up at the rear of our new list. p
	// moves through the list we are copying
	node<T> *newNode, *p = q.qfront;

	// initially, the list is empty
	qfront = qback = NULL;

	// nothing to do if p is NULL
	if (p != NULL)
	{
		// create the first node in the queue and assign
		// its addres to qback
		qfront = qback = getNode(p->nodeValue);

		// move forward in the list we are copying
		p = p->next;

		// copy remaining items
		while(p != NULL)
		{
			// insert new node at the back
			newNode = getNode(p->nodeValue);
			qback->next = newNode;

			// qback is the new node
			qback = newNode;

			// move to the next node of the list we are copying
			p = p->next;
		}
	}

	// the size of the new list is the size of q
	qsize = q.qsize;
}

template <typename T>
void linkedQueue<T>::clear()
{
	node<T> *curr = qfront, *p;

	// delete nodes until we arrive at the end of the list
	while (curr != NULL)
	{
		// save curr in p and move curr forward
		// to the next list node
		p = curr;
		curr = curr->next;

		// delete node p
		delete p;
	}

	// specify an emtpy list
	qfront = qback = NULL;
	qsize = 0;
}

template <typename T> // hafızada boş alan bulup node yaratır.
node<T> *linkedQueue<T>::getNode(const T& item)
{
	// allocate a new node
	node<T> *newNode = new node<T> (item);

	// check for failure
	if (newNode == NULL)
	  cout<<"Hata !";

	return newNode;
}

// create the empty list qfront = qback = NULL and qsize = 0
template <typename T>
linkedQueue<T>::linkedQueue(): qfront(NULL), qback(NULL), qsize(0)
{}

template <typename T>
linkedQueue<T>::linkedQueue(const linkedQueue<T>& obj)
{
	// call copy() and pass the pointer to the front of
	// the linked list in obj
	copy(obj);
}

template <typename T>
linkedQueue<T>::~linkedQueue()
{
	// call clear()
	clear();
}

template <typename T>
linkedQueue<T>& linkedQueue<T>::operator= (const linkedQueue<T>& rhs)
{
	// delete the current list
	clear();

	// make the current object a copy of rhs
	copy(rhs);

	return *this;
}

// insert item into the queue by inserting it at
// the back of the list
template <typename T>
void linkedQueue<T>::push(const T& item)
{
	// allocate space for the new node
	node<T> *newNode = getNode(item);

	// if the queue is empty, insert the new element at the front of
	// the list and update both qfront and qback
	if (qfront == NULL)
	{
		qfront = newNode;
		qback = newNode;
	}
	// in a non-empty list, insert new element at back and update qback
	else
	{
		qback->next = newNode;
		qback = newNode;
	}

	// increment the queue size
	qsize++;
}

// remove the item at the front of the queue by erasing
// the first element in the linked list
template <typename T>
void linkedQueue<T>::pop()
{
	// save the location of the front of the queue
	node<T> *p = qfront;

	// if the queue is empty, throw underflowError
	if (qsize == 0)
      cout<<"Boy = 0";

	// move the front forward one node
	qfront= qfront->next;

	// if the queue is now empty, set qback to NULL
	if (qfront == NULL)
		qback = NULL;

	// delete the node
	delete p;

	// decrement the queue size
	qsize--;
}

template <typename T>
T& linkedQueue<T>::front()
{
	// if the queue is empty, throw underflowError
	if (qsize == 0)
      cout<<"Queue boyu 0";

	// return the value at the front
	return qfront->nodeValue;
}

template <typename T>
const T& linkedQueue<T>::front() const
{
	// if the queue is empty, throw underflowError
	if (qsize == 0)
             cout<<"Queue boyu 0";

	// return the value at the front
	return qfront->nodeValue;
}

template <typename T>
int linkedQueue<T>::size() const
{
	return qsize;
}

template <typename T>
bool linkedQueue<T>::empty() const
{
	return qsize == 0;
}

int main()
{
	// declare an integer array and compute its size
	int arr[] = {6, 9, 2, 5}, i;
	int arrSize = sizeof(arr)/sizeof(int);

	// declare an empty queue of integer elements
	linkedQueue<int> q;

	// insert the array elements in q and output their value
	for (i = 0; i < arrSize; i++)
		q.push(arr[i]);

	// display the resulting size of the queue
	cout << "Queue size is " << q.size() << endl;

	// clear the queue
	while (!q.empty())
	{
		// display the element at the front and then
		// erase it from the queue
		cout << q.front() << "  ";
		q.pop();
	}
	cout << endl;

system("pause");
	// handle the underflowError exception thrown by a call to pop()

	return 0;
}

Kodu izleyerek beklenen çıktı:

Queue size is 4
6  9  2  5

Kuyruk FIFO olduğu için elemanlar eklendikleri sırayla (6, 9, 2, 5) çıkıyor.

Not: Dosyanın sonundaki örnek çalışmada bir de "queue pop(): empty queue" satırı var; bu satır, istisna fırlatan özgün kitap sürümünün çıktısı. Bu uyarlamada boş kuyrukta pop() çağrılmıyor ve hata durumunda istisna yerine yalnızca mesaj yazıldığı için bu satır basılmaz. Ayrıca mesaj yazıldıktan sonra fonksiyon devam ettiği için boş kuyrukta pop() ya da front() çağrılırsa NULL işaretçi kullanılır; mesajdan sonra fonksiyondan çıkılmalı.

eem227-sirali-ekleme-bagli-kuyruk.zip

ZIP arşivi · 4 KB · 13.12.2007

⬇ (4 KB)