diff --git a/smooth-heap.c b/smooth-heap.c
new file mode 100644
index 0000000000000000000000000000000000000000..c7a1ffa11775a9de193b402fa17ecf6ae5cf059a
--- /dev/null
+++ b/smooth-heap.c
@@ -0,0 +1,377 @@
+/*
+                     Smooth heap implementation
+
+  The "Smooth heap" is a simple and efficient self-adjusting priority queue, 
+  with similarities to the Pairing heap. It supports the operations:
+    * insert        
+    * find_min
+    * delete_min
+    * decrease_key
+    * merge
+    * delete
+  
+  Smooth and slim heaps are described in the papers:
+   * L. Kozma, T. Saranurak: "Smooth heaps and a dual view of self-adjusting
+      data structures" SIAM J. Comput. 49(5) (2020)
+      https://arxiv.org/abs/1802.05471
+   * M. Hartmann, L. Kozma, C. Sinnamon, R. Tarjan: "Analysis of smooth heaps
+      and slim heaps" ICALP (2021)
+
+  The implementation uses a straightforward pointer-structure, loosely 
+  inspired by D. Sleator's implementation of the Splay tree.  It is based on
+  a single multi-ary tree where each node stores a key, according to the 
+  (min-)heap order, so that the key of a non-root node is at least the key
+  of its parent.  Each node has the pointers: left (sibling), right (sibling), 
+  and rightmost (child).  Siblings are linked into a doubly-linked, almost*
+  circular list.
+  (* The left pointer of each leftmost child points back to the parent,
+  this allows us to get away without using parent pointers.)
+
+  Additional data can be stored in the nodes as necessary.
+
+  Compile: gcc smooth-heap.c -lm
+
+  This code was written by L. Kozma <laszlo.kozma@fu-berlin.de> 
+  and is released into the public domain. 
+
+  Version 0.02, May 2021.
+  Latest version: www.lkozma.net/slim-heap.c  and   www.lkozma.net/smooth-heap.c
+
+*/
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#define INT_MIN -2147483648
+
+/*  The structure holding single nodes as well as the entire heap.  */
+
+typedef struct heap_node Heap;
+struct heap_node {
+    Heap * left, * right, * rightmost;
+    int key;
+};
+
+
+/*  Create a new node with a given key. 
+    Return a pointer to the new node. 
+    Needed if we may insert this node later using insertn.  */
+
+Heap * new_node(int i) {
+
+   Heap * n;
+   n = (Heap *) malloc (sizeof (Heap));
+   if (!n) {
+	printf("Ran out of space\n");
+	exit(1);
+   }
+   n->key = i;
+   n->left = n->right = n; 
+   n->rightmost = NULL;
+   return n;
+}
+
+
+/*  Insert heap node n into the heap h.  
+    Return a pointer to the modified heap.  
+    This variant to be used if pointer to inserted node  
+      needed later e.g. for decrease-key or delete.  */
+
+Heap * insertn(Heap * n, Heap * h) {
+
+    Heap * rm;
+    if (!h || n->key < h->key) {
+	n->rightmost = h;
+	return n;
+    }
+    rm = h->rightmost;
+    if (!rm) {                    /*  h has no child  */
+        n->left = h;
+        h->rightmost = n;
+        return h;
+    } else {                      /*  h has a child  */
+        n->right = rm->right;
+        n->left = rm;
+        rm->right = n;
+        h->rightmost = n;
+        return h;
+    }
+}
+
+
+/*  Insert key i into the heap h.   
+    Return a pointer to the modified heap.  */
+
+Heap * insert(int i, Heap * h) {
+
+    Heap * n, * h2;
+    n = new_node(i);
+    h2 = insertn(n,h);
+    return h2;
+}
+
+
+/*  Findmin needs no function.  For heap h, the minimum key is h->key.
+    The node with minimum key is simply h.  */
+
+
+/*  Link heaps parent and child, assuming both exist. 
+    Return a pointer to the resulting heap. 
+    link1 assumes parent was left sibling of child. 
+    link2 assumes parent was right sibling of child. 
+    This is also the linking primitive used by other operations.  */
+ 
+Heap * link1(Heap * parent, Heap * child) {
+
+    Heap * rm;
+    rm = parent->rightmost;
+    if (!rm) {
+        child->left = parent;
+        child->right = child;
+    } else {
+        child->right = rm->right;
+        child->left = rm;
+        rm->right = child;
+    }
+    parent->rightmost = child;
+    return parent;
+}
+
+Heap * link2(Heap * parent, Heap * child) {
+
+    Heap * rm;
+    rm = parent->rightmost;
+    child->left = parent;
+    if (!rm) {
+        child->right = child;
+        parent->rightmost = child;
+    } else {
+        child->right = rm->right;
+        rm->right->left = child;
+        rm->right = child;
+    }
+    return parent;
+}
+
+
+/*  Merge heaps h1 and h2. Return a pointer to the resulting heap. 
+    Also used by some other operations. */
+ 
+Heap * merge(Heap * h1, Heap * h2) {
+
+    Heap * rm, * parent, * child;
+    int lr = 0;
+    if (!h1)  
+        return h2;
+    if (!h2 || h1 == h2)
+        return h1;
+    if (h1->key < h2->key) {
+        parent = h1;
+        child = h2;
+        lr = 1;
+    } else {
+        parent = h2;
+        child = h1;
+    }
+
+    if (lr) 
+        link1(parent, child);
+    else
+        link2(parent, child);
+}
+
+
+/*  Print keys of the heap in preorder.  Useful for debugging.  */
+
+void print(Heap *h) {
+
+    Heap * x, * lm, *rm;
+    if (h) {
+        printf("%d | ", h->key);
+        rm = h->rightmost;
+        if (rm) {
+            x = lm = rm->right;
+            do {
+                print(x);
+                x = x->right;
+                printf("- ");
+            } while (x != lm);
+            printf("^ ");
+        }
+    }    
+}
+
+
+/*  Decrease key of node n in heap h to k. 
+    Return a pointer to the resulting heap. 
+    It is the user's responsibility to ensure that n exists within h,
+    otherwise all bets are off.  */
+
+Heap * decrease_key(Heap * n, Heap * h, int k) {
+
+    Heap * h2, * nl, * nr;    
+    if (!h || !n) {
+        printf("Error: heap or node empty!\n");
+        exit(1);
+    } 
+    if (n->key < k) {
+        printf("Error: decrease_key trying to increase!\n");
+        exit(1);
+    }
+    n->key = k;    
+    if (n == h)                             /*  n is the root  */
+        return h;
+    nl = n->left;
+    nr = n->right;
+    if (nr == n) {                          /*  n is a unique child  */
+        nl->rightmost = NULL;          
+    } else if (nr->left->rightmost == n) {  /*  n is a rightmost child  */
+        nl->right = nr;
+        nr->left->rightmost = nl;
+    } else if (nl->rightmost && nl->rightmost->right == n) { 
+        nl->rightmost->right = nr;          /*  n is a leftmost child  */
+        nr->left = nl;
+    } else {                                /*  none of the above  */
+        nl->right = nr;
+        nr->left = nl;
+    }
+    n->left = n->right = n;
+    h2 = merge(h, n);
+    return h2;    
+}
+
+
+/*  Delete the minimum-key node (i.e. the root) of heap h. 
+    This is where the restructuring specific to smooth heaps happens.
+    Return a pointer to the resulting heap after restructuring.  */
+
+Heap * delete_min(Heap * h) {
+
+    Heap * x, * tl, *tr, *rm;
+    if (!h) {
+        printf("Error: heap empty!\n");
+        exit(1);
+    } 
+    rm = h->rightmost;
+    if (!rm)
+        return NULL;
+
+    x = rm->right;                                  /*  close off margins  */
+    x->left = NULL;                                  
+    rm->right = NULL;
+
+    while (x->right) {                              /*  left-to-right phase  */
+        if (x->key < x->right->key)
+            x = x->right;
+        else {                                      /*  x is a local max  */
+            while ((x->left) && (x->left->key > x->right->key)) { /*  link left  */
+                tr = x->right;
+                x = link1(x->left, x);
+                tr->left = x;
+                x->right = tr;
+            }
+            tl = x->left;                                         /*  link right  */
+            tr = x->right->right;
+            x = link2(x->right, x); 
+            if (tl)
+                tl->right = x;
+            x->left = tl; 
+        }    
+    }
+    while (x->left) {                               /*  right-to-left phase  */
+        x = link1(x->left, x);
+    }
+    x->left = x->right = x;
+    free(h);
+    return x;
+}
+
+
+/*  Delete node n in heap h. 
+    Return a pointer to the resulting heap.  
+    It is the user's responsibility to ensure that n exists within h,
+    otherwise all bets are off.  */
+ 
+Heap * delete(Heap * n, Heap * h) {
+
+    Heap * h2;
+    h2 = decrease_key(n, h, INT_MIN);
+    h2 = delete_min(h2);
+    return h2;
+}
+
+
+/*  A sample use of these functions.  Start with the empty heap,         
+    insert some stuff into it, and play around with the operations.  */
+
+void main() {
+    Heap * heap, * heap2, * heap3, * heap4, * temp, * temp2;
+    int z, i;
+    heap = NULL;               /* the empty heap */
+    heap = insert(10, heap);
+    heap = insert(20, heap);
+    heap = insert(5, heap);
+    temp = new_node(25);
+    heap = insertn(temp, heap);
+    heap = insert(30, heap);
+    heap = insert(9, heap);
+    heap = insert(50, heap);
+    heap = insert(6, heap);
+    heap = insert(100, heap);
+    heap = insert(120, heap);
+    heap = insert(90, heap);
+
+    heap2 = NULL;
+    heap2 = insert(4, heap2);
+    heap2 = insert(8, heap2);
+    temp2 = new_node(11);
+    heap2 = insertn(temp2, heap2);
+    heap2 = insert(3, heap2);
+
+    heap3 = NULL;
+    heap3 = merge(heap2, heap);
+    print(heap3);
+    printf("#\n");
+
+    heap3 = delete_min(heap3);
+    print(heap3);
+    printf("#\n");
+
+    heap3 = delete_min(heap3);
+    print(heap3);
+    printf("#\n");
+
+    heap3 = decrease_key(temp2, heap3, 1);
+    print(heap3);
+    printf("#\n");
+
+    heap3 = delete_min(heap3);
+    print(heap3);
+    printf("#\n");
+
+    heap3 = delete_min(heap3);
+    print(heap3);
+    printf("#\n");
+
+    heap3 = delete(temp, heap3);
+    print(heap3);
+    printf("#\n");
+
+    heap4 = NULL;             
+    for (i=1;i<10000;i++) {
+        z = (i*973133) % 10000;
+        heap4 = insert(z, heap4);
+        //printf("%d\n", z);
+    }
+
+    //printf("\n\n");
+    //print(heap4);
+    //printf("#\n");
+
+    for (i=1;i<10000;i++) {
+        //printf("%d.%d\n", i, heap4->key);
+        heap4 = delete_min(heap4);
+    }
+
+
+}