Ah pardon, per qualche motivo avevo inteso partizionamento in un altro senso... comunque, mi pare che sia corretta; sui tuoi due casi:
- p non presente: non è un problema, nel codice non cerchi mai l'eguaglianza con p, ma solo il > o il <=;
- p è presente più volte: anche qui, proprio perché non cerchi l'uguaglianza ma le disuguaglianze di cui sopra, è possibile partizionare, semplicemente la zona dei >p inizierà solo dopo l'ultima occorrenza di p.
L'i<j è sempre verificato s all'inizio del do lo era (dato che i due while modificano i e j solo se i<j); l'unico caso in cui si può avere i<j quindi è se alla prima iterazione i>=j (ovvero, se n=0 o n=1); per n=1 non è un problema, per n=0 (e j=-1) può essere un problema per il secondo while (vai a guardare array[-1].P.S l'if(i<j) prima della chiamata alla funzione change può anche essere omesso ma mi sembra rischioso, tu che consigli?
Per questo motivo, toglierei l'if e cambierei il do...while in un semplice while, per evitare di entrare nel ciclo nel caso n=0.