Shortest implementation of a linked list, stack and queue

5

1

Challenge

Write the shortest program that implements the minimum requirements for a linked list, stack and queue.

Minimum requirements

  • Functions that allow the user to add and remove elements from the linked list, stack and queue.
  • Any data type can be added to the linked list, stack and queue (string, int, etc.).
  • One special function (e.g. sort letters alphabetically).
  • The program must work (compile without errors and operations and results should make sense in the context of linked lists, stacks and queues)!
  • Lastly, this program must be hard-coded. Arrays, however, are allowed (please refer to the restrictions section).

Winning criteria

  • Standard Codegolf rules.
  • Number of characters based on the summation of characters for linked list, stack and queue.

Restrictions

  • No trivial answers (i.e. 0 or 1 for a stack based language).
  • You are allowed to write the program in any language except for stack-based languages (let me know if this is unfair).
  • You cannot simply use the functions of another class. If a language (like Ruby) already has push and pop functions in arrays or any other class, you must write your own push and pop functions.

Little blurb: If this code golf challenge is too simple, I will add more requirements. I'm also open to any suggestions.

Rob

Posted 2013-11-08T21:08:28.110

Reputation: 1 277

Mhh, not really clear. What prevents me from doing class A extends java.util.Stack {}? – Johannes Kuhn – 2013-11-08T22:13:53.097

@JohannesKuhn Good point, updated. – Rob – 2013-11-08T22:24:42.620

2what if, for example, in Ruby arrays have push, pop, and shift, so technically arrays are stacks and queues. They behave like linked lists, because linked lists are basically just arrays, so the default array already pretty much meets these requirements... – Doorknob – 2013-11-08T22:34:24.717

@Doorknob So "hard-coded functionality" would be better wording for this question? I guess restricting trivial answers is too generic... I'll think of a better way to word "trivial". – Rob – 2013-11-08T23:43:55.647

1I don't know how I could do this without using arrays... – Doorknob – 2013-11-08T23:49:23.297

@Doorknob You can. I want people to write their own push and pop functions, not use the defaults already implemented in the language. – Rob – 2013-11-08T23:51:44.490

So, we only need to write push, pop, and shift functions? I'll do it now – Doorknob – 2013-11-09T02:08:10.820

@Doorknob Hmm, this question sounded a lot better in my head... Oh well. At least it will be good practice for beginners. – Rob – 2013-11-09T13:30:57.740

@Doorknob But in that case you just have a single Deque/List hybrid, not a separate list, stack, and queue (though the question doesn't seem to specify that they have to be separate) – SuperJedi224 – 2017-05-24T11:15:50.307

Answers

4

Haskell, 81 69 characters

data L a=N|a:~L a
N~:z=z:~N
(a:~b)~:z=a:~(b~:z)
r N=N
r(a:~z)=r z~:a

This code makes use of no preexisting functions at all. The push operation is :~, the enqueue operation is ~:. Both pop and dequeue are via pattern match against :~. The extra operation r is reverse.

Stacks:

ex1 =
    let stack0 = N                      -- empty stack
        stack1 = 'a' :~ stack0          -- push 'a'
        stack2 = 'b' :~ stack1          -- push 'b'
        first :~ stack3 = stack2        -- pop
        second :~ stack4 = stack3       -- pop
    in mapM_ print [first, second]

λ: ex1
'b'
'a'

Queues:

ex2 =
    let queue0 = N                      -- empty queue
        queue1 = queue0 ~: 'x'          -- enq 'x'
        queue2 = queue1 ~: 'y'          -- enq 'y'
        queue3 = queue2 ~: 'z'          -- enq 'z'
        next0 :~ queue4 = queue3        -- deq
        next1 :~ queue5 = queue4        -- deq
        next2 :~ queue6 = queue5        -- deq
    in mapM_ print [next0, next1, next2]

λ: ex2
'x'
'y'
'z'

List reverse operation:

ex3 =
    let list = "alpha" :~ ("beta" :~ ("gamma" :~ N)) -- a list
        tsil = r list                   -- reverse the list
        native N = []                   -- convert to native list
        native (a:~z) = a : native z    -- for easy printing
    in mapM_ (print . native) [list, tsil]

λ: ex3
["alpha","beta","gamma"]
["gamma","beta","alpha"]

MtnViewMark

Posted 2013-11-08T21:08:28.110

Reputation: 4 779

1

Ruby, 123

class S
def initialize
@a=[]
end
def u n
@a[@a.size]=n
end
def o
@a.slice! -1
end
def s
@a.slice!0
end
def j x
@a*x
end
end

Example:

s = S.new     # initialize
s.u 5         # push 5
s.u 10        # push 10
s.u [1,2,3]   # push [1,2,3]
s.u "test"    # push "test"
s.u "test2"   # push "test2"
puts s.s      # shift - queue behaivior (remove and return first element, 5)
puts s.o      # pop - stack behaivior (remove and return last element, "test2")
puts s.j ", " # join - special behavior (join elements with argument, "10, 1, 2, 3, test")

Doorknob

Posted 2013-11-08T21:08:28.110

Reputation: 68 138

0

C, 659 bytes

Try Online

typedef M;typedef struct M{int d;M*n;M*p;}Q;typedef struct{Q*f;Q*e;}L;Q*t;x;
Q*F(L**l){return*l?(*l)->f:0;}
Q*E(L**l){return*l?(*l)->e:0;}
N(Q**t){*t=*t?(*t)->n:0;}
P(Q**t){*t=*t?(*t)->p:0;}
A(L**l,int d){Q*t=(Q*)malloc(sizeof(Q));t->d=d;if(*l)(*l)->f->p=t,t->n=(*l)->f,(*l)->f=t;else(*l)=(L*)malloc(sizeof(L)),(*l)->f=t,(*l)->e=t;}
B(L**l){if(*l)t=(*l)->f,(*l)->f=t->n,(*l)->f->p=0,x=t->d,free(t);if(!(*l)->f)free(*l);return x;}
C(L**l,int d){t=(Q*)malloc(sizeof(Q));t->d=d;if(*l)(*l)->e->n=t,t->p=(*l)->e,(*l)->e=t;else (*l)=(L*)malloc(sizeof(L)),(*l)->f=t,(*l)->e=t;}
D(L**l){if(*l)t=(*l)->e,(*l)->e=t->p,(*l)->e->n=0,x=t->d,free(t);if(!(*l)->e)free(*l);return x;}

Detailed github

typedef _LNode; typedef struct _LNode{ void* d; _LNode* n; _LNode* p; } LNode;
typedef _List; typedef struct _List{ LNode* f; LNode* e; int size; } List;

LNode* list_begin(List** l){ return *l?(*l)->f:0; }
LNode* list_end(List** l){ return *l?(*l)->e:0; }

void list_iterator_next(LNode** t){ *t = *t?(*t)->n:0; }
void list_iterator_prev(LNode** t){ *t = *t?(*t)->p:0; }

int list_size(List** l){ return *l?(*l)->size:0; }

void list_push_front(List** l, void* d)
{
    LNode*t = (LNode)malloc(sizeof(LNode));
    t->d = d;

    if(*l)
        (*l)->f->p = t,
        t->n = (*l)->f,
        (*l)->f = t;
    else
        (*l)=(List*)malloc(sizeof(List)),
        (*l)->f = t,
        (*l)->e = t;

    (*l)->size++;
}

void list_push_back(List** l, void* d)
{
    LNode*t = (LNode)malloc(sizeof(LNode));
    t->d = d;

    if(*l)
        (*l)->e->n = t,
        t->p = (*l)->e,
        (*l)->e = t;
    else
        (*l)=(List*)malloc(sizeof(List)),
        (*l)->f = t,
        (*l)->e = t;

    (*l)->size++;
}

void* list_pop_front(List** l)
{
    LNode* t = 0;
    void* d = 0;

    if(*l)
        t = (*l)->f,
        (*l)->f = t->n,
        (*l)->f->p = 0,
        d = t->d,
        free(t),
        (*l)->size--;

    if(!(*l)->f) free(*l);

    return d;
}

void* list_pop_back(List** l)
{
    LNode* t = 0;
    void* d = 0;

    if(*l)
        t = (*l)->e,
        (*l)->e = t->p,
        (*l)->e->n = 0,
        d = t->d,
        free(t),
        (*l)->size--;

    if(!(*l)->e) free(*l);

    return d;
}

Khaled.K

Posted 2013-11-08T21:08:28.110

Reputation: 1 435

I think you can ditch the casts before malloc(). Also, you can replace sizeof(Q) with sizeof*t – ceilingcat – 2017-07-01T06:56:20.493

0

JavaScript, 188

function L(){N=null;E=[N,N];t=this;h=E;t.u=i=>h=[i,h];
t.o=_=>h==E?N:h[+!(h=h[1])];t.e=(i,l)=>h=(l||h)==E?[i, 
E]:[(l||h)[0],t.e(i,(l||h)[1])];t.s=_=>{o="";while(i=t.o())
{o+=i+","}return o}}

(Line breaks added for readability, not needed for answer or counted as bytes)

Usage

Methods

  • u(item): Push
  • o() -> item: Pop (or dequeue)
  • e(item): Enqueue
  • s() -> string: Convert to a string

Example

let failed = _ => { throw Error(); };
let list = new L();

// Stack
list.u(1);
list.u(3);

list.o() === 3 || failed();
list.u(2);
list.o() === 2 || failed();
list.o() === 1 || failed();
list.o() === null || failed();

// Queue

list.e(1);
list.e(2);

list.o() === 1 || failed();
list.e(3);
list.o() === 2 || failed();
list.o() === 3 || failed();
list.o() === null || failed();

// Reverse
list.u(1);
list.u(2);
list.u(3);

list.s() === "3,2,1," || failed();

Explanation

function L(){
    N=null; // end marker
    // a node has the format [item, rest]
    E=[N,N]; // end marker, is a node
    t=this;
    h=E; // head of list, is a node

    t.d = _ => JSON.stringify(h);

    t.u=i=>h=[i,h]; // push

    t.o=_=> // pop/deque
        h==E?
        N:
        h[+!(h=h[1])]; // set head to rest, return item (index into zeroth index by casting an assignment to a value to a bool to a float)

    // t.e acts recursively, we use `||` to set a default for when the user calls
    t.e=(i,l)=> // enqueue (user caller leaves `l` undefined)
        h=
            (l||h)==E?
                [i, E]: // if at end, insert new item right before
                [(l||h)[0],t.e(i,(l||h)[1])]; // else keep current value and process rest recursively

    t.s=_=>{
        o="";
        while(i=t.o()) {
            o+=i+","
        }
        return o
    }
}

Notes

List can't store anything JavaScript casts to false (null, false, 0, [], etc.). Repeated pop operations on an empty list have no effect. Ignore the return values of push and enqueue. Because I use global variables to reduce character count, only one list can be created.

Daniel Franklin

Posted 2013-11-08T21:08:28.110

Reputation: 73