Bidirectional bubble sort is a variation to the well known bubble sort but adds an extra level of efficiency in terms of speed.
It iterates through the list of elements not only from the beginning to the end as the bubble sort does but also from the end to beginning in reverse order, reducing the overall sorting time by dynamically limiting the number of elements being iterated through.
It is also known as cocktail shaker sort, shaker sort, double-direction bubble sort and is also an “in place sorting algorithm” which means that no extra RAM memory is needed to sort the list elements.
The bidirectional bubble sort works by (1)iterating up the array to be sorted from the first element to the last, comparing each pair of elements and swapping their positions if necessary. The last swap index position is remembered to become the next upper limit of forward iteration.(2)Right after the forward iteration, follows a backward iteration starting from last upper index down to the lower index limit comparing each pair of elements and swapping their positions if necessary.The last swap index position is remembered to become the next lower limit of the backward iteration.The whole 2 step cycle repeats itself until the two limits - upper and lower - become equal.
Let us see an example of sorting an array to make the idea of bidirectional bubble sort clearer, using AVR assembler to implement it.
Unordered list.
{12, 0, 13, 5, 16, 0, 17, 18}
Forward iteration.
During the first forward iteration the initial upper and lower limits are index #7 and #0 respectively. The iteration will start from the lower index limit which happens to be #0 in the beginning.
Number 16 will bubble up, swapping up since it is the biggest number in the iteration.The iteration will stop when the upper index limit is reached.
As a result the upper index limit will change to #5(the last index where a swap happened) as indexes above it are already sorted.
Backward iteration.
The backward iteration starts from the upper index limit down to lower index limit swapping adjacent numbers if necessary.
Number 0(index #4) will bubble down, swapping all the way down since it is the smallest number in this iteration.
As a result the lower index limit will change to #1(the last index where a swap happened) as indexes under it are already sorted.
The same sequence of forward and backward iteration repeats until the lower and upper index limit become the same(equal).
Implementation.
Avr assembler implementation is prepared for 8 and 16 bits signed and unsigned numbers.
Signed 1 byte Bi-Directional Bubble sort.
#define BUFFER_SIZE 256
#define INDEX_LIMIT BUFFER_SIZE-1 ;zero based index
.dseg
buffer: .byte BUFFER_SIZE
.cseg
/************************8 bit Sigend Bi-directional Bubble Sort*************
;Sort unsigned bytes between 0 and 255
@AUTHOR: Sergey Iliev
@INPUT:RAM buffer to sort
@USAGE: right,left,k,cnt,axl,bxl,
Z - buffer item pointer
@OUTPUT: RAM buffer sorted out
**************************************************************/
Signed8bitBiDirectBubbleSort:
ldi right,INDEX_LIMIT ;size of array - 1
ldi left,0
sbbsort:
clr k
;first loop iterate forward
ldi ZL,low(BUFFER)
ldi ZH,high(BUFFER)
clr temp
mov cnt,left
ADD16 ZL,ZH,cnt,temp
sbb_loopr:
ld axl,Z+
ld bxl,Z
cp bxl,axl
brge sbb_loopr1 ;signed
st -Z,bxl
adiw Z,1
st Z,axl
mov k,cnt
sbb_loopr1:
inc cnt
cp cnt,right
brlo sbb_loopr
mov right,k
ldi cnt,INDEX_LIMIT
mov k,cnt
;exit if no sawp happened or first position swap
tst right
brne sbb_loopl0
ret
sbb_loopl0:
;second loop iterate backward
ldi ZL,low(BUFFER)
ldi ZH,high(BUFFER)
clr temp
mov cnt,right
ADD16 ZL,ZH,cnt,temp
sbb_loopl:
ld axl,Z
ld bxl,-Z
cp bxl,axl
brlt sbb_loopl1 ;signed
st Z,axl
std Z+1,bxl
mov k,cnt
sbb_loopl1:
dec cnt
cp left,cnt
brlo sbb_loopl
mov left,k
cp left,right
brlo sbbsort
ret
Unsigned 1 byte Bi-Directional Bubble sort.
/************************8 bit Unsigend Bi-directional Bubble Sort*************
;Sort unsigned bytes between 0 and 255
@AUTHOR: Sergey Iliev
@INPUT:RAM buffer to sort
@USAGE: right,left,k,cnt,axl,bxl,
Z - buffer item pointer
@OUTPUT: RAM buffer sorted out
**************************************************************/
Unsigned8bitBiDirectBubbleSort:
ldi right,INDEX_LIMIT ;size of array - 1
ldi left,0
ubbsort:
clr k
;first loop iterate forward
ldi ZL,low(BUFFER)
ldi ZH,high(BUFFER)
clr temp
mov cnt,left
ADD16 ZL,ZH,cnt,temp
ubb_loopr:
ld axl,Z+
ld bxl,Z
cp bxl,axl
brsh ubb_loopr1 ;unsigned
st -Z,bxl
adiw Z,1
st Z,axl
mov k,cnt
ubb_loopr1:
inc cnt
cp cnt,right
brlo ubb_loopr
mov right,k
ldi cnt,INDEX_LIMIT
mov k,cnt
;exit if no sawp happened or first position swap
tst right
brne ubb_loopl0
ret
ubb_loopl0:
;second loop iterate backward
ldi ZL,low(BUFFER)
ldi ZH,high(BUFFER)
clr temp
mov cnt,right
ADD16 ZL,ZH,cnt,temp
ubb_loopl:
ld axl,Z
ld bxl,-Z
cp bxl,axl
brlo ubb_loopl1 ;unsigned
st Z,axl
std Z+1,bxl
mov k,cnt
ubb_loopl1:
dec cnt
cp left,cnt
brlo ubb_loopl
mov left,k
cp left,right
brlo ubbsort
ret
Signed 2 byte Bi-Directional Bubble sort.
#define BUFFER_SIZE16 520
#define INDEX_LIMIT16 BUFFER_SIZE16-1 ;zero based index
.dseg
buffer16: .byte BUFFER_SIZE16*2
.cseg
/****************16 bit Signed Bi-Directional Bubble/Coctail/Shuffle Sort************
*@AUTHOR: Sergey Iliev
*@INPUT:RAM buffer with unsigned words to sort
*@USAGE:Z - pointer to buffer beginning
rightl,righth - marks the last index(rightmost) 2 adjacent numbers have been exchanged
leftl,lefth - marks the last index(leftmost) 2 adjacent numbers have been exchanged
cntl:cnth - index
axl:axh,bxl:bxh - words to compare
kxl:kxh - help variable
*@OUTPUT:RAM buffer sorted out!
*****************************************************************************************/
Signed16bitBiDirectBubbleSort:
ldi rightl,low(INDEX_LIMIT16) ;size of array - 1
ldi righth,high(INDEX_LIMIT16)
//set lower address boundery
ldi leftl,low(0)
ldi lefth,high(0)
sbbsort16:
;prepare for left to right itteration
clr kh
clr kl
;first loop iterate forward
ldi ZL,low(BUFFER16)
ldi ZH,high(BUFFER16)
mov cnth,lefth
mov cntl,leftl
;position to the left-most un-ordered element
LSL16 cnth,cntl ;multiply by 2 ->dealing with 2 bytes/word content
ADD16 ZL,ZH,cntl,cnth
;restore cnt
mov cnth,lefth
mov cntl,leftl
sbb_loopr16:
ld axl,Z+
ld axh,Z+
ld bxl,Z
ldd bxh,Z+1
CP16 bxl,bxh,axl,axh
brge sbb_loopr116 ;signed
st -Z,bxh ;exchange words
st -Z,bxl
adiw Z,2
st Z,axl
std Z+1,axh
;remember last rightmost unordered position
mov kl,cntl
mov kh,cnth
sbb_loopr116:
ADDI16 cntl,cnth,1
;did it get to the last previously unordered position
CP16 cntl,cnth,rightl,righth
brlo sbb_loopr16
mov rightl,kl
mov righth,kh
;exit if no sawp happened or first position swap
CPI16 rightl,righth,cntl,0
brne sbb_loopl0
ret
;----------------reverse iteration----------------------------
sbb_loopl0:
;prepare for the right to left iterration
ldi ZL,low(BUFFER16)
ldi ZH,high(BUFFER16)
mov kl,rightl
mov kh,righth
mov cntl,rightl
mov cnth,righth
;second loop iterate backward
LSL16 cnth,cntl ;multiply by 2 ->dealing with 2 bytes/word content
ADD16 ZL,ZH,cntl,cnth
//restore cnt
mov cntl,rightl
mov cnth,righth
sbb_loopl16:
ldd axh,Z+1
ld axl,Z
ld bxh,-Z
ld bxl,-Z
CP16 bxl,bxh,axl,axh
brlt sbb_loopl116 ;signed
st Z+,axl
st Z+,axh
st Z,bxl
std Z+1,bxh
ADDI16 ZL,ZH,-2
;remember last leftmost unordered position
mov kl,cntl
mov kh,cnth
sbb_loopl116:
ADDI16 cntl,cnth,-1
;did it get to the last previously unordered position
CP16 leftl,lefth,cntl,cnth
brlo sbb_loopl16
mov leftl,kl
mov lefth,kh
CP16 leftl,lefth,rightl,righth
brlo asbbsort16
ret
asbbsort16:
rjmp sbbsort16
Unsigned 2 byte Bi-Directional Bubble sort.
/******************16 bit Unsigned Bi-Directional Bubble/Coctail/Shuffle Sort*********
*@AUTHOR: Sergey Iliev
*@INPUT:RAM buffer with unsigned words to sort
*@USAGE:Z - pointer to buffer beginning
rightl,righth - marks the last index(rightmost) 2 adjacent numbers have been exchanged
leftl,lefth - marks the last index(leftmost) 2 adjacent numbers have been exchanged
cntl:cnth - index
axl:axh,bxl:bxh - words to compare
kxl:kxh - help variable
*@OUTPUT:RAM buffer sorted out!
*****************************************************************************************/
Unsigned16bitBiDirectBubbleSort:
ldi rightl,low(INDEX_LIMIT16) ;size of array - 1
ldi righth,high(INDEX_LIMIT16)
//set lower address boundery
ldi leftl,low(0)
ldi lefth,high(0)
ubbsort16:
;prepare for left to right itteration
clr kh
clr kl
;first loop iterate forward
ldi ZL,low(BUFFER16)
ldi ZH,high(BUFFER16)
mov cnth,lefth
mov cntl,leftl
;position to the left-most un-ordered element
LSL16 cnth,cntl ;multiply by 2 ->dealing with 2 bytes/word content
ADD16 ZL,ZH,cntl,cnth
;restore cnt
mov cnth,lefth
mov cntl,leftl
ubb_loopr16:
ld axl,Z+
ld axh,Z+
ld bxl,Z
ldd bxh,Z+1
CP16 bxl,bxh,axl,axh
brsh ubb_loopr116 ;unsigned
st -Z,bxh ;exchange words
st -Z,bxl
adiw Z,2
st Z,axl
std Z+1,axh
;remember last rightmost unordered position
mov kl,cntl
mov kh,cnth
ubb_loopr116:
ADDI16 cntl,cnth,1
;did it get to the last previously unordered position
CP16 cntl,cnth,rightl,righth
brlo ubb_loopr16
mov rightl,kl
mov righth,kh
;exit if no sawp happened or first position swap
CPI16 rightl,righth,cntl,0
brne ubb_loopl0
ret
;----------------reverse iteration----------------------------
ubb_loopl0:
;prepare for the right to left iterration
ldi ZL,low(BUFFER16)
ldi ZH,high(BUFFER16)
mov kl,rightl
mov kh,righth
mov cntl,rightl
mov cnth,righth
;second loop iterate backward
LSL16 cnth,cntl ;multiply by 2 ->dealing with 2 bytes/word content
ADD16 ZL,ZH,cntl,cnth
//restore cnt
mov cntl,rightl
mov cnth,righth
ubb_loopl16:
ldd axh,Z+1
ld axl,Z
ld bxh,-Z
ld bxl,-Z
CP16 bxl,bxh,axl,axh
brlo ubb_loopl116 ;unsigned
st Z+,axl
st Z+,axh
st Z,bxl
std Z+1,bxh
ADDI16 ZL,ZH,-2
;remember last leftmost unordered position
mov kl,cntl
mov kh,cnth
ubb_loopl116:
ADDI16 cntl,cnth,-1
;did it get to the last previously unordered position
CP16 leftl,lefth,cntl,cnth
brlo ubb_loopl16
mov leftl,kl
mov lefth,kh
CP16 leftl,lefth,rightl,righth
brlo aubbsort16
ret
aubbsort16:
rjmp ubbsort16