/* -*- mode: c; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */ /********************************************************************* * Clustal Omega - Multiple sequence alignment * * Copyright (C) 2010 University College Dublin * * Clustal-Omega is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This file is part of Clustal-Omega. * ********************************************************************/ /* * RCS $Id: list-C.h 143 2010-10-14 13:11:14Z andreas $ */ // list.C // Class for double-linked list #ifndef JLIST #define JLIST #ifndef MAIN #include // cin, cout #include // #include // using std::cout; using std::cerr; #endif #include "list.h" //////////////////////////////////////////////////////////////////////////// // Double-linked list implementation with head and tail dummy elements // We set head->prev=head and tail->next=tail. // This makes sure that repeated current=current->next; ends up in tail // and repeated current=current->prev; ends up in head. // head and tail optionally contain a NULL element of Typ defined by method Null(Typ) //////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////// // Constructors and destructor //////////////////////////////////////////////////////////////////////////// // Creates empty List with two dummy elements //////////////////////////////////////////////////////////////////////////// template List::List() { head=new ListEl(); if (!head) { cerr<<"Could not create new element\n"; return; } tail=new ListEl(head,NULL); if (!tail) { cerr<<"Could not create new element\n"; return; } tail->next = tail; head->prev = head; head->next = tail; current = head; size=0; } //////////////////////////////////////////////////////////////////////////// // Creates List with one element //////////////////////////////////////////////////////////////////////////// template List::List(Typ d) { head=new ListEl(); if (!head) { cerr<<"Could not create new element\n"; return; } tail=new ListEl(); if (!tail) { cerr<<"Could not create new element\n"; return; } ListEl* el = new ListEl(d,head,tail); if (!el) { cerr<<"Could not create new element\n"; return; } head->prev = head; head->next = el; tail->prev = el; tail->next = tail; current = head; size=1; } //////////////////////////////////////////////////////////////////////////// // Destructor deletes List object //////////////////////////////////////////////////////////////////////////// template List::~List() { ListEl* n=head->next; while(head!=n) { delete(head); head = NULL; head=n; n=head->next; } delete(head); head = NULL; } //////////////////////////////////////////////////////////////////////////// // Flat copy //////////////////////////////////////////////////////////////////////////// template List& List::operator=(List& l) { head = l.head; tail = l.tail; current = l.current; size = l.size; } //////////////////////////////////////////////////////////////////////////// // Reverse order of list //////////////////////////////////////////////////////////////////////////// template void List::Reverse() { ListEl *n; // next list element; also for swapping ListEl *c; // current element to be sorted in. Everything to the left is already sorted if (Size()<=1) return; for (c=head; c!=tail; c=n) { // Swap prev and next pointers of all list elements n = c->next; c->next = c->prev; c->prev = n; } // Swap prev and next pointers of tail tail->next = tail->prev; tail->prev = tail; // Swap head an tail n = head; head = tail; tail = n; } //////////////////////////////////////////////////////////////////////////// // Methods that act at the end of the list //////////////////////////////////////////////////////////////////////////// // Insert Element after LAST of list (and return address of data element) //////////////////////////////////////////////////////////////////////////// template Typ* List::Push(Typ d) { ListEl* t=new ListEl(d,tail->prev,tail); if (!t) { cerr<<"Could not create new element\n"; return 0; } tail->prev->next=t; tail->prev = t; size++; return &(t->data); } //////////////////////////////////////////////////////////////////////////// // Remove and return LAST element of list. Returns head->data if empty //////////////////////////////////////////////////////////////////////////// template Typ List::Pop() { if (!size) return head->data; ListEl* t=tail->prev; if (current==t) current=tail; Typ d=t->data; t->prev->next=tail; tail->prev=t->prev; delete t; t = NULL; size--; return d; } //////////////////////////////////////////////////////////////////////////// // Methods that act at the beginning of the list //////////////////////////////////////////////////////////////////////////// // Insert element as FIRST element of list (and return address of data element) //////////////////////////////////////////////////////////////////////////// template Typ* List::Enqueue(Typ d) { ListEl* h = new ListEl(d,head,head->next); if (!h) { cerr<<"Could not create new element\n"; return 0; } h->next->prev = h; head->next=h; size++; return &(h->data); } //////////////////////////////////////////////////////////////////////////// // Remove element at BEGINNING of list //////////////////////////////////////////////////////////////////////////// template Typ List::Dequeue() { if (!size) return head->data; ListEl* h=head->next; if (current==h) current=head; Typ d=h->data; h->next->prev=head; head->next=h->next; delete h; h = NULL; size--; return d; } //////////////////////////////////////////////////////////////////////////// // Methods that work with 'current' position in the list //////////////////////////////////////////////////////////////////////////// // Reads next element; advances current position by 1 //////////////////////////////////////////////////////////////////////////// template inline Typ List::ReadNext() { current = current->next; return current->data; } //////////////////////////////////////////////////////////////////////////// // Reads current element again (NULL if nothing read yet) //////////////////////////////////////////////////////////////////////////// template inline Typ List::ReadCurrent() { return current->data; } //////////////////////////////////////////////////////////////////////////// // Reads previous element; moves current position back by 1 //////////////////////////////////////////////////////////////////////////// template inline Typ List::ReadPrevious() { current = current->prev; return current->data; } //////////////////////////////////////////////////////////////////////////// // Reads next element; advances current position by 1 //////////////////////////////////////////////////////////////////////////// template inline Typ* List::ReadNextAddress() { current = current->next; if (current==tail) return NULL; return &(current->data); } //////////////////////////////////////////////////////////////////////////// // Reads address of current element again, returns NULL if at end of list //////////////////////////////////////////////////////////////////////////// template inline Typ* List::ReadCurrentAddress() { if (current==tail) return NULL; return &(current->data); } //////////////////////////////////////////////////////////////////////////// // Sets current position to k and reads k'th element (first=1) //////////////////////////////////////////////////////////////////////////// template Typ List::Read(int pos) { if (pos>size) {current = tail; return tail->data;} if (pos<=0) {current = head; return head->data;} current = head->next; for (; pos>1; pos--) current = current->next; //If pos==2 do 1 iteration return current->data; } //////////////////////////////////////////////////////////////////////////// // Inserts element d AFTER current element and sets current element to inserted //////////////////////////////////////////////////////////////////////////// template void List::Insert(Typ d) { ListEl* el = new ListEl(d,current,current->next); if (!el) { cerr<<"Could not create new element\n"; return; } (current->next)->prev = el; current->next = el; current=el; size++; } //////////////////////////////////////////////////////////////////////////// // Deletes current element and returns content of deleted element. Current element // will be previous one after Delete(). After Reset() delete first element (not 0'th) //////////////////////////////////////////////////////////////////////////// template Typ List::Delete() { Typ d; ListEl* p; if (!size || current==tail) return tail->data; if (current==head) current = head->next; // After Reset() delete first element (not 0'th) (current->prev)->next = current->next; (current->next)->prev = current->prev; d = current->data; p = current->prev; delete current; current = NULL; current = p; size--; return d; } //////////////////////////////////////////////////////////////////////////// // Methods that return useful information about the list //////////////////////////////////////////////////////////////////////////// // Get current position within list (0 <= pos <= Size+1) //////////////////////////////////////////////////////////////////////////// template int List::GetPos() { int pos=0; ListEl* el; for (el = head; el!=current; el=el->next) pos++; return pos; } //////////////////////////////////////////////////////////////////////////// //print out list //////////////////////////////////////////////////////////////////////////// template void List::PrintList() { int j=0; ListEl* c=current; Reset(); printf("List: "); while (!End()) { j++; cout< Typ List::Largest() { Typ* result= &((tail->prev)->data); Reset(); while (!End()) { if (*result Typ List::Smallest() { Typ* result= &((tail->prev)->data); Reset(); while (!End()) { if (ReadNext()<*result) result=ReadCurrentAddress(); } return *result; } ///////////////////////////////////////////////////////////////////////////// // Methods that manipulate the list as a whole //////////////////////////////////////////////////////////////////////////// // Copies list 0 into list object //////////////////////////////////////////////////////////////////////////// template void List::Copy(List* list) { if (list==this) return; while (!End()) Pop(); //empty list list->Reset(); while (!list->End()) Push(list->ReadNext()); } //////////////////////////////////////////////////////////////////////////// // Appends a copy of list2 to class object //////////////////////////////////////////////////////////////////////////// template void List::AppendCopy(List* list2) { List* cpy=new List; cpy->Copy(list2); Append(cpy); delete cpy; cpy = NULL; } //////////////////////////////////////////////////////////////////////////// // Appends list2 to class object //////////////////////////////////////////////////////////////////////////// template void List::Append(List* list) { if (this==list) { AppendCopy(list); return;} (tail->prev)->next = list->head->next; (list->head->next)->prev = tail->prev; if (current==tail) current=tail->prev; ListEl* t=tail; tail = list->tail; size += list->size; // Reuse old tail as new tail t for list2 and initialize pointers for empty list list->tail=t; list->head->next=t; t->prev=list->head; t->next=t; list->head->prev=list->head; t->data=list->head->data; list->current=list->head; list->size = 0; } //////////////////////////////////////////////////////////////////////////// // Use QUICKSORT to sort list in ascending order between two list elements //////////////////////////////////////////////////////////////////////////// template void List::SortList(ListEl* left, ListEl* right, int sz) { if (sz<=1) return; // when SortList() is called, left=head->next, right=tail->prev ListEl *l=left->prev, *r=right->next; // Choose *random* pivot element!! // (Otherwise, complexity for an already sorted list is N^2 => recursive calls may lead to stack overflow) ListEl *c=left; for (int i=1; i<(int)(float(rand())*sz/(RAND_MAX+0.999)); i++) c = c->next; SwapContent(left,c); Typ pivot = left->data; // Typ* pivot= &(left->data); int sz0=sz+1; // cout<<"Sorting between "<data<<" and "<data<<". Pivot="<prev; sz0--;} while (pivot < r->data); do l=l->next; while (l->data < pivot); if (l==r || l->prev==r) break; SwapContent(l,r); } SortList(left,r,sz0); SortList(r->next,right,sz-sz0); pivot = tail->data; // to avoid calling the destructor of Typ on some real data element } //////////////////////////////////////////////////////////////////////////// // Use QUICKSORT to sort list of POINTERS by comparing the objects the pointers point to //////////////////////////////////////////////////////////////////////////// template void List::SortPointerList(ListEl* left, ListEl* right) { if (right==left || right->next==left) return; ListEl *l=left->prev, *r=right->next; Typ pivot=left->data; // cout<<"Sorting between "<data<<" and "<data<<". Pivot="<prev; // cout<<"r=r->prev. r->data="<data<data)); do { l=l->next; // cout<<"l=l->next l->data="<data<data) < *pivot); if (l==r || l->prev==r) break; SwapContent(l,r); } SortPointerList(left,r); SortPointerList(r->next,right); } // Use INSERTSORT to sort list in asscending order between two list elements. Use only for presorted lists, otherwise time O(N^2)! template void List::ResortList() { ListEl *c; // current element to be sorted in. Everything to the left is already sorted ListEl *n; // next element to be sorted in ListEl *p; // pointer for looping through sorted part of list ListEl *pnext; // for swapping if (Size()<=1) return; c=head->next->next; while (c!=tail) { p=c->prev; n=c->next; if (c->data < p->data) { do {p=p->prev;} while (p!=head && c->data < p->data); // Connect c->prev to c->next ... c->next->prev=c->prev; c->prev->next=c->next; // ... and insert c between p and p->next ... pnext=p->next; p->next=c; c->next=pnext; pnext->prev=c; c->prev=p; } c=n; } } #endif /* JLIST */ // //Main program: test class List // int main() // { // int p; // List* plist=new List(11); // List list(22); // plist->Push(24); // plist->Push(18); // plist->Push(3); // plist->Enqueue(17); // plist->Enqueue(29); // printf("List 1 with pushed and enqueued elements:\n"); // plist->PrintList(); // list.Push(222); // printf("List 1 with list 2 appended:\n"); // plist->Append(&list); // plist->PrintList(); // printf("Pushing one element three times into list 2:\n"); // list.Push(333); // list.Push(444); // list.Push(555); // printf("Printing plist and list with three elements:\n"); // list.PrintList(); // plist->PrintList(); // printf("list.Copy(plist). Printing list 1 and 2:\n"); // list.Copy(plist); // plist->PrintList(); // list.PrintList(); // printf("Appending list 1 to itself:\n"); // plist->Append(plist); // plist->PrintList(); // cout<<"Popping "<Pop()<<"\n"; // cout<<"Popping "<Pop()<<"\n"; // plist->PrintList(); // cout<<"Dequeing "<Dequeue()<<"\n"; // cout<<"Dequeing "<Dequeue()<<"\n"; // plist->PrintList(); // cout<<"Reversing list\n"; // plist->Reverse(); // plist->PrintList(); // cout<<"Reversing to original list\n"; // plist->Reverse(); // plist->PrintList(); // for (p=plist->Reset(); p>=5;p--) // {cout<GetPos()<<": "<Read(p)<<"\n";} // cout<<"Deleting "<Delete()<<"\n"; // cout<<"Deleting "<Delete()<<"\n"; // plist->PrintList(); // plist->Append(plist); // plist->PrintList(); // cout<<"List 1 sorted:\n"; // plist->SortList(); // plist->PrintList(); // }