6 * $Date: 2012-07-16 14:23:36 +0200 (Mo, 16. Jul 2012) $
7 ***************************************************************/
10 * \brief Declaration and implementation of Array class and
13 * \author Carsten Gutwenger
16 * This file is part of the Open Graph Drawing Framework (OGDF).
20 * See README.txt in the root directory of the OGDF installation for details.
23 * This program is free software; you can redistribute it and/or
24 * modify it under the terms of the GNU General Public License
25 * Version 2 or 3 as published by the Free Software Foundation;
26 * see the file LICENSE.txt included in the packaging of this file
30 * This program is distributed in the hope that it will be useful,
31 * but WITHOUT ANY WARRANTY; without even the implied warranty of
32 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
33 * GNU General Public License for more details.
36 * You should have received a copy of the GNU General Public
37 * License along with this program; if not, write to the Free
38 * Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
39 * Boston, MA 02110-1301, USA.
41 * \see http://www.gnu.org/copyleft/gpl.html
42 ***************************************************************/
53 #include <ogdf/basic/basic.h>
58 //! Iteration over all indices \a i of an array \a A.
60 * Note that the index variable \a i has to be defined prior to this macro
61 * (just as for \c #forall_edges, etc.).
68 * forall_arrayindices(i, A) {
69 * cout << A[i] << endl;
73 * Note that this code is equivalent to the following tedious long version
79 * for(i = A.low(); i <= A.high(); ++i) {
80 * cout << A[i] << endl;
84 #define forall_arrayindices(i, A) \
85 for(i = (A).low(); i<=(A).high(); ++i)
87 //! Iteration over all indices \a i of an array \a A, in reverse order.
89 * Note that the index variable \a i has to be defined prior to this macro
90 * (just as for \c #forall_edges, etc.).
91 * See \c #forall_arrayindices for an example
93 #define forall_rev_arrayindices(i, A) \
94 for(i = (A).high(); i>=(A).low(); --i)
98 //! The parameterized class \a Array<E,INDEX> implements dynamic arrays of type \a E.
100 * @tparam E denotes the element type.
101 * @tparam INDEX denotes the index type. The index type must be chosen such that it can
102 * express the whole index range of the array instance, as well as its size.
103 * The default index type is \c int, other possible types are \c short and
104 * <code>long long</code> (on 64-bit systems).
106 template<class E
, class INDEX
= int> class Array
{
108 //! Threshold used by \a quicksort() such that insertion sort is
109 //! called for instances smaller than \a maxSizeInsertionSort.
110 enum { maxSizeInsertionSort
= 40 };
113 //! Creates an array with empty index set.
114 Array() { construct(0,-1); }
116 //! Creates an array with index set [0..\a s-1].
117 explicit Array(INDEX s
) {
118 construct(0,s
-1); initialize();
121 //! Creates an array with index set [\a a..\a b].
122 Array(INDEX a
, INDEX b
) {
123 construct(a
,b
); initialize();
126 //! Creates an array with index set [\a a..\a b] and initializes each element with \a x.
127 Array(INDEX a
, INDEX b
, const E
&x
) {
128 construct(a
,b
); initialize(x
);
131 //! Creates an array that is a copy of \a A.
132 Array(const Array
<E
> &A
) {
141 //! Returns the minimal array index.
142 INDEX
low() const { return m_low
; }
144 //! Returns the maximal array index.
145 INDEX
high() const { return m_high
; }
147 //! Returns the size (number of elements) of the array.
148 INDEX
size() const { return m_high
- m_low
+ 1; }
150 //! Returns a pointer to the first element.
151 E
*begin() { return m_pStart
; }
153 //! Returns a pointer to the first element.
154 const E
*begin() const { return m_pStart
; }
156 //! Returns a pointer to one past the last element.
157 E
*end() { return m_pStop
; }
159 //! Returns a pointer to one past the last element.
160 const E
*end() const { return m_pStop
; }
162 //! Returns a pointer to the last element.
163 E
*rbegin() { return m_pStop
-1; }
165 //! Returns a pointer to the last element.
166 const E
*rbegin() const { return m_pStop
-1; }
168 //! Returns a pointer to one before the first element.
169 E
*rend() { return m_pStart
-1; }
171 //! Returns a pointer to one before the first element.
172 const E
*rend() const { return m_pStart
-1; }
174 //! Returns a reference to the element at position \a i.
175 const E
&operator[](INDEX i
) const {
176 OGDF_ASSERT(m_low
<= i
&& i
<= m_high
)
180 //! Returns a reference to the element at position \a i.
181 E
&operator[](INDEX i
) {
182 OGDF_ASSERT(m_low
<= i
&& i
<= m_high
)
186 //! Swaps the elements at position \a i and \a j.
187 void swap(INDEX i
, INDEX j
) {
188 OGDF_ASSERT(m_low
<= i
&& i
<= m_high
)
189 OGDF_ASSERT(m_low
<= j
&& j
<= m_high
)
191 std::swap(m_vpStart
[i
], m_vpStart
[j
]);
194 //! Reinitializes the array to an array with empty index set.
201 //! Reinitializes the array to an array with index set [0..\a s-1].
203 * Notice that the elements contained in the array get discarded!
205 void init(INDEX s
) { init(0,s
-1); }
207 //! Reinitializes the array to an array with index set [\a a..\a b].
209 * Notice that the elements contained in the array get discarded!
211 void init(INDEX a
, INDEX b
) {
217 //! Reinitializes the array to an array with index set [\a a..\a b] and sets all entries to \a x.
218 void init(INDEX a
, INDEX b
, const E
&x
) {
224 //! Assignment operator.
225 Array
<E
,INDEX
> &operator=(const Array
<E
,INDEX
> &array2
) {
231 //! Sets all elements to \a x.
232 void fill(const E
&x
) {
234 while(pDest
> m_pStart
)
238 //! Sets elements in the intervall [\a i..\a j] to \a x.
239 void fill(INDEX i
, INDEX j
, const E
&x
) {
240 OGDF_ASSERT(m_low
<= i
&& i
<= m_high
)
241 OGDF_ASSERT(m_low
<= j
&& j
<= m_high
)
243 E
*pI
= m_vpStart
+ i
, *pJ
= m_vpStart
+ j
+1;
248 //! Enlarges the array by \a add elements and sets new elements to \a x.
250 * Note: address of array entries in memory may change!
251 * @param add is the number of additional elements; \a add can be negative in order to shrink the array.
252 * @param x is the inital value of all new elements.
254 void grow(INDEX add
, const E
&x
);
256 //! Enlarges the array by \a add elements.
258 * Note: address of array entries in memory may change!
259 * @param add is the number of additional elements; \a add can be negative in order to shrink the array.
261 void grow(INDEX add
);
263 //! Randomly permutes the subarray with index set [\a l..\a r].
264 void permute (INDEX l
, INDEX r
);
266 //! Randomly permutes the array.
268 permute(low(), high());
271 //! Performs a binary search for element \a x.
273 * \pre The array must be sorted!
274 * \return the index of the found element, and low()-1 if not found.
276 inline int binarySearch (const E
& x
) const {
277 return binarySearch(x
, StdComparer
<E
>());
280 //! Performs a binary search for element \a x with comparer \a comp.
282 * \pre The array must be sorted according to \a comp!
283 * \return the index of the found element, and low()-1 if not found.
285 template<class COMPARER
>
286 int binarySearch(const E
& e
, const COMPARER
&comp
) const {
288 if(size() == 1 && comp
.equal(e
, m_vpStart
[low()]))
296 if(comp
.greater(e
, m_vpStart
[m
]))
301 return comp
.equal(e
, m_vpStart
[l
]) ? l
: low()-1;
304 //! Performs a linear search for element \a x.
306 * Warning: This method has linear running time!
307 * Note that the linear search runs from back to front.
308 * \return the index of the found element, and low()-1 if not found.
310 inline int linearSearch (const E
& e
) const {
312 for(i
= size(); i
-->0;)
313 if(e
== m_pStart
[i
]) break;
316 //! Performs a linear search for element \a x with comparer \a comp.
318 * Warning: This method has linear running time!
319 * Note that the linear search runs from back to front.
320 * \return the index of the found element, and low()-1 if not found.
322 template<class COMPARER
>
323 int linearSearch(const E
& e
, const COMPARER
&comp
) const {
325 for(i
= size(); i
-->0;)
326 if(comp
.equal(e
, m_pStart
[i
])) break;
330 //! Sorts array using Quicksort.
331 inline void quicksort() {
332 quicksort(StdComparer
<E
>());
335 //! Sorts subarray with index set [\a l..\a r] using Quicksort.
336 inline void quicksort(INDEX l
, INDEX r
) {
337 quicksort(l
, r
, StdComparer
<E
>());
340 //! Sorts array using Quicksort and a user-defined comparer \a comp.
342 * @param comp is a user-defined comparer; \a C must be a class providing a \a less(x,y) method.
344 template<class COMPARER
>
345 inline void quicksort(const COMPARER
&comp
) {
347 quicksortInt(m_pStart
,m_pStop
-1,comp
);
350 //! Sorts the subarray with index set [\a l..\a r] using Quicksort and a user-defined comparer \a comp.
352 * @param l is the left-most position in the range to be sorted.
353 * @param r is the right-most position in the range to be sorted.
354 * @param comp is a user-defined comparer; \a C must be a class providing a \a less(x,y) method.
356 template<class COMPARER
>
357 void quicksort(INDEX l
, INDEX r
, const COMPARER
&comp
) {
358 OGDF_ASSERT(low() <= l
&& l
<= high())
359 OGDF_ASSERT(low() <= r
&& r
<= high())
361 quicksortInt(m_vpStart
+l
,m_vpStart
+r
,comp
);
364 template<class F
, class I
> friend class ArrayBuffer
; // for efficient ArrayBuffer::compact-method
367 E
*m_vpStart
; //!< The virtual start of the array (address of A[0]).
368 E
*m_pStart
; //!< The real start of the array (address of A[m_low]).
369 E
*m_pStop
; //!< Successor of last element (address of A[m_high+1]).
370 INDEX m_low
; //!< The lowest index.
371 INDEX m_high
; //!< The highest index.
373 //! Allocates new array with index set [\a a..\a b].
374 void construct(INDEX a
, INDEX b
);
376 //! Initializes elements with default constructor.
379 //! Initializes elements with \a x.
380 void initialize(const E
&x
);
382 //! Deallocates array.
385 //! Constructs a new array which is a copy of \a A.
386 void copy(const Array
<E
,INDEX
> &A
);
388 //! Internal Quicksort implementation with comparer template.
389 template<class COMPARER
>
390 static void quicksortInt(E
*pL
, E
*pR
, const COMPARER
&comp
) {
393 // use insertion sort for small instances
394 if (s
< maxSizeInsertionSort
) {
395 for (E
*pI
= pL
+1; pI
<= pR
; pI
++) {
398 while (--pJ
>= pL
&& comp
.less(v
,*pJ
)) {
406 E
*pI
= pL
, *pJ
= pR
;
410 while (comp
.less(*pI
,x
)) pI
++;
411 while (comp
.less(x
,*pJ
)) pJ
--;
412 if (pI
<= pJ
) std::swap(*pI
++,*pJ
--);
415 if (pL
< pJ
) quicksortInt(pL
,pJ
,comp
);
416 if (pI
< pR
) quicksortInt(pI
,pR
,comp
);
425 // enlarges array by add elements and sets new elements to x
426 template<class E
, class INDEX
>
427 void Array
<E
,INDEX
>::grow(INDEX add
, const E
&x
)
429 INDEX sOld
= size(), sNew
= sOld
+ add
;
431 // expand allocated memory block
433 E
*p
= (E
*)realloc(m_pStart
, sNew
*sizeof(E
));
434 if(p
== 0) OGDF_THROW(InsufficientMemoryException
);
437 m_pStart
= (E
*)malloc(sNew
*sizeof(E
));
438 if (m_pStart
== 0) OGDF_THROW(InsufficientMemoryException
);
441 m_vpStart
= m_pStart
-m_low
;
442 m_pStop
= m_pStart
+sNew
;
445 // initialize new array entries
446 for (E
*pDest
= m_pStart
+sOld
; pDest
< m_pStop
; pDest
++)
450 // enlarges array by add elements (initialized with default constructor)
451 template<class E
, class INDEX
>
452 void Array
<E
,INDEX
>::grow(INDEX add
)
454 INDEX sOld
= size(), sNew
= sOld
+ add
;
456 // expand allocated memory block
458 E
*p
= (E
*)realloc(m_pStart
, sNew
*sizeof(E
));
459 if(p
== 0) OGDF_THROW(InsufficientMemoryException
);
462 m_pStart
= (E
*)malloc(sNew
*sizeof(E
));
463 if (m_pStart
== 0) OGDF_THROW(InsufficientMemoryException
);
466 m_vpStart
= m_pStart
-m_low
;
467 m_pStop
= m_pStart
+sNew
;
470 // initialize new array entries
471 for (E
*pDest
= m_pStart
+sOld
; pDest
< m_pStop
; pDest
++)
475 template<class E
, class INDEX
>
476 void Array
<E
,INDEX
>::construct(INDEX a
, INDEX b
)
478 m_low
= a
; m_high
= b
;
482 m_pStart
= m_vpStart
= m_pStop
= 0;
485 m_pStart
= (E
*)malloc(s
*sizeof(E
));
486 if (m_pStart
== 0) OGDF_THROW(InsufficientMemoryException
);
488 m_vpStart
= m_pStart
- a
;
489 m_pStop
= m_pStart
+ s
;
494 template<class E
, class INDEX
>
495 void Array
<E
,INDEX
>::initialize()
499 for (; pDest
< m_pStop
; pDest
++)
502 while(--pDest
>= m_pStart
)
510 template<class E
, class INDEX
>
511 void Array
<E
,INDEX
>::initialize(const E
&x
)
515 for (; pDest
< m_pStop
; pDest
++)
518 while(--pDest
>= m_pStart
)
526 template<class E
, class INDEX
>
527 void Array
<E
,INDEX
>::deconstruct()
529 if (doDestruction((E
*)0)) {
530 for (E
*pDest
= m_pStart
; pDest
< m_pStop
; pDest
++)
537 template<class E
, class INDEX
>
538 void Array
<E
,INDEX
>::copy(const Array
<E
,INDEX
> &array2
)
540 construct(array2
.m_low
, array2
.m_high
);
543 E
*pSrc
= array2
.m_pStop
;
545 while(pDest
> m_pStart
)
546 //*--pDest = *--pSrc;
547 new (--pDest
) E(*--pSrc
);
552 // permutes array a from a[l] to a[r] randomly
553 template<class E
, class INDEX
>
554 void Array
<E
,INDEX
>::permute (INDEX l
, INDEX r
)
556 OGDF_ASSERT(low() <= l
&& l
<= high())
557 OGDF_ASSERT(low() <= r
&& r
<= high())
559 E
*pI
= m_vpStart
+l
, *pStart
= m_vpStart
+l
, *pStop
= m_vpStart
+r
;
561 std::swap(*pI
++,*(pStart
+randomNumber(0,r
-l
)));
565 // prints array a to output stream os using delimiter delim
566 template<class E
, class INDEX
>
567 void print(ostream
&os
, const Array
<E
,INDEX
> &a
, char delim
= ' ')
569 for (int i
= a
.low(); i
<= a
.high(); i
++) {
570 if (i
> a
.low()) os
<< delim
;
577 template<class E
, class INDEX
>
578 ostream
&operator<<(ostream
&os
, const ogdf::Array
<E
,INDEX
> &a
)
584 } // end namespace ogdf