The circular linked list operations keep the ring and return the right result full
This proof shows: correctness.
Invariant (I). If L.n=0, then $L.last = $ NIL. If n=L.n≥1, the items are held in distinct nodes v0,…,vn−1 with vi.next=vi+1 for 0≤i<n−1, vn−1.next=v0, and L.last=vn−1. The list held is (ℓ0,…,ℓn−1) with ℓi=vi.key.
For each operation we assume (I) and the precondition, and show (I) for the list that the type asks for. Each push adds 1 to the count and each pop subtracts 1, so we only check the nodes and pointers.
PUSH-FRONT(L,x). Line L1 makes a new node v, distinct from the old nodes. If n=0, line L2 sets v.next=v and L.last=v: this is (I) for n=1 with v0=v, and the list (x). If n≥1, line L3 first sets v.next=L.last.next=vn−1.next=v0, then sets vn−1.next=v. Define w0=v and wi=vi−1 for 1≤i≤n. Then w0.next=v0=w1; wi.next=vi=wi+1 for 1≤i≤n−1, since those fields are unchanged; and wn.next=vn−1.next=v=w0. The nodes are distinct and L.last=vn−1=wn. So (I) holds for (x,ℓ0,…,ℓn−1).
PUSH-BACK(L,x). After line L4, (I) holds for (x,ℓ0,…,ℓn−1) with nodes w0=v,w1,…,wn and L.last=wn. Line L5 sets L.last=wn.next=w0=v. Read the same ring from L.last.next=w1: define ui=wi+1 for 0≤i≤n−1 and un=w0. Then ui.next=ui+1 for i<n, un.next=w1=u0, and L.last=un. So (I) holds for (ℓ0,…,ℓn−1,x). When n=0 the ring is the single node v and L.last=v.next=v, which is (I) for (x).
POP-FRONT(L), n≥1. Line L6 sets v=vn−1.next=v0. If n=1, then v0=vn−1=L.last, line L7 sets $L.last = $ NIL, and (I) holds for the empty list. If n≥2, then v=L.last, and line L7 sets vn−1.next=v0.next=v1. The nodes v1,…,vn−1 are distinct, vi.next=vi+1 for 1≤i<n−1 (unchanged), vn−1.next=v1, and L.last=vn−1. So (I) holds for (ℓ1,…,ℓn−1), and line L8 returns ℓ0.
ROTATE(L), n≥1. Line L9 sets L.last=vn−1.next=v0. No next field changes. Define ui=vi+1 for 0≤i≤n−2 and un−1=v0. Then ui.next=ui+1 for i<n−1, un−1.next=v1=u0 (or v0=u0 when n=1), and L.last=un−1. So (I) holds for (ℓ1,…,ℓn−1,ℓ0), which is the list with its front moved to the back. ■