{"id":17464542,"url":"https://github.com/hqarroum/circular-linked-list","last_synced_at":"2025-06-13T13:34:02.593Z","repository":{"id":35157076,"uuid":"39392526","full_name":"HQarroum/circular-linked-list","owner":"HQarroum","description":":cyclone: An implementation of a circular doubly-linked list in C.","archived":false,"fork":false,"pushed_at":"2024-09-15T00:21:37.000Z","size":4759,"stargazers_count":8,"open_issues_count":0,"forks_count":3,"subscribers_count":4,"default_branch":"master","last_synced_at":"2024-12-25T16:40:50.915Z","etag":null,"topics":["algorithm","linked-list"],"latest_commit_sha":null,"homepage":"","language":"C","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/HQarroum.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2015-07-20T15:38:40.000Z","updated_at":"2024-09-15T00:21:40.000Z","dependencies_parsed_at":"2024-07-19T10:02:55.837Z","dependency_job_id":"a0086a8a-3997-4faf-9582-1fb324dbe4f5","html_url":"https://github.com/HQarroum/circular-linked-list","commit_stats":null,"previous_names":[],"tags_count":1,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/HQarroum%2Fcircular-linked-list","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/HQarroum%2Fcircular-linked-list/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/HQarroum%2Fcircular-linked-list/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/HQarroum%2Fcircular-linked-list/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/HQarroum","download_url":"https://codeload.github.com/HQarroum/circular-linked-list/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":232110905,"owners_count":18474035,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["algorithm","linked-list"],"created_at":"2024-10-18T10:46:15.731Z","updated_at":"2025-01-01T18:34:21.039Z","avatar_url":"https://github.com/HQarroum.png","language":"C","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003cbr/\u003e\u003cbr/\u003e\n\u003cp align=\"center\"\u003e\n  \u003cimg src=\"./assets/icon.png\" /\u003e\n\u003c/p\u003e\n\u003cbr/\u003e\n\n# circular-linked-list\n[![CI](https://github.com/HQarroum/circular-linked-list/actions/workflows/main.yml/badge.svg)](https://github.com/HQarroum/circular-linked-list/actions/workflows/main.yml)\n\n\u003e An implementation of a tiny circular doubly-linked list in C.\n\nCurrent version: **1.0.1**\n\n## Building and testing\n\nThis implementation builds as a dynamic and a static library by default. In order to trigger the build, simply call the Makefile at the root of the project using `make`.\n\nThis project is tested using the `Google Test` framework, the tests are located in the `tests/` directory and have their own Makefile which produce an executable. To launch the tests simply call the produced `launch_tests` executable.\n\n## Creating an instance of a list\n\nAn instance of a list is of type `list_t`.\n\nA list holds its current size which is represented as the sum of its nodes that are of type `node_t`. It also contains a pointer to the head of the list, and a pointer to the tail of the list.\n\n### Creating a list dynamically\n\nIn order to create a new instance of a list on the heap, you must call `list_create`.\n\n```C\nlist_t* list = list_create();\n```\n\n### Creating a list statically\n\nIf you feel you do not need a pointer to be returned and you'd like the list to be created statically, you can call `list_create_static` :\n\n```C\nlist_t list = list_create_static();\n```\n\n\u003e Do not forget to clear the list when you are finished using a static instance, typically using `list_clear` in order for all the nodes to be properly deleted.\n\n## Inserting elements\n\nElements you can push into an instance of a `list_t` are of type `void*`.\n\nThere are two ways to insert an element into an instance of a list :\n\n```C\n// Pushing elements to head.\nlist_push_front(list, \"foo\");\nlist_push_front(list, \"bar\");\n\n// Pushing elements to tail.\nlist_push_back(list, \"baz\");\nlist_push_back(list, \"qux\");\n```\n\nBoth functions create an instance of a `node_t` which wraps the given element to insert in the list. Both functions return a pointer to the created node.\n\n\u003e The complexity of a node insertion is constant `O(1)`.\n\n## Popping elements\n\nYou can *pop* an element located at the head or at the tail of the list. Popping an element will remove the inserted `node` and return a pointer to the value that was associated with that node.\n\n```C\n// Will return the constant string `qux`.\nconst char* qux = list_pop_back(list);\n\n// Will return the constant string `bar`.\nconst char* bar = list_pop_front(list).\n```\n\n\u003e The complexity of a node pop is constant `O(1)`.\n\n## Iterating over the nodes\n\n### Using a callback\n\nIt is possible to iterate over each nodes associated with a list by having a function called back on each node :\n\n```C\nint iterator(size_t index, node_t* node, void* data) {\n  printf(\"Node (%zu) element : %s\\n\", index,\n    (const char*) node-\u003eelement);\n  return (0);\n}\n\nlist_iterate_over_nodes(list, iterator, NULL);\n```\n\nThis method will allow you to iterate from the first element (the head of the list) to the last element (the tail of the list). If a negative value is returned from the iterator, the iteration will stop.\n\n### Using an iterator\n\nAnother way of iterating over the list is by using the iterator APIs. The main difference with using a callback is that you are in full control of the iteration, you can stop it, but also go forward or backward.\n\nTo do so, first create a `list_iterator_t` and use it to traverse the list.\n\n```C\nlist_iterator_t it = list_make_iterator(list, NULL);\n\nfor (size_t i = 0; i \u003c list_get_size(list)\n         \u0026\u0026 list_iterator_has_next(\u0026it); ++i) {\n  node_t* node = list_iterator_next(\u0026it);\n  // Do something with `node`.\n}\n```\n\n\u003e ℹ️ The second parameter of `list_make_iterator` is optional, it specifies a node pointer you'd like the iterator to start at. If NULL is specified, the iterator will start at the head of the list.\n\nThe iterator created by `list_make_iterator` will indefinitely iterate over the list (unless it is empty), since the list is circular. This is why we used a counter in the above example to stop the iteration at the end of the list.\n\nNote that you are encouraged to write your own iterator functions that will implement the appropriate logic of how to iterate over an instance of a list given your application requirements.\n\n\u003e The complexity of an iteration over each node in the list is linear `O(n)`.\n\n## Finding an element\n\n### Basic node lookup\n\nIt is possible to search through the list for a particular node. You can use the `list_find_node` function to do so.\n\n```C\nnode_t* node = list_push_front(list, \"foo\");\n\nif (list_find_node(list, node)) {\n  // `node` was found\n}\n```\n\n### Conditional lookup\n\nTo customize the way to find an element in the list you can provide a predicate function to the `list_find_node_if` function :\n\n```C\nint predicate(size_t index, node_t* node, void* data) {\n  return (!strcmp(node-\u003eelement, data));\n}\n\nif (list_find_node_if(list, predicate, \"foo\")) {\n  // `foo` was found\n}\n```\n\n\u003e The complexity of both basic and customized lookups is linear `O(n)`.\n\n## Removing a node\n\n### Basic removal\n\nTo remove a given node from the list, you can pass a pointer to the node you'd like to be removed to the `list_remove_node` function :\n\n```C\nlist_t* list = list_create();\nnode_t* node = list_push_front(list, \"foo\");\n\n// Remove the node from the list.\nlist_remove_node(list, node);\n```\n\n### Conditional removal\n\nIt is possible to remove a node using a more functional way, by using a predicate passed to `list_remove_node_if`.\n\n```C\nint predicate(size_t index, node_t* node, void* data) {\n  return (!strcmp(node-\u003eelement, \"bar\")\n          || !strcmp(node-\u003eelement, \"foo\"));\n}\n\n// Remove from the list each node holding\n// the constant strings 'foo' or 'bar'.\nlist_remove_node_if(list, predicate, NULL);\n```\n\nIt is also possible to pass a third parameter to `list_remove_node_if`, for it to be passed to your predicate function.\n\n```C\nint predicate(size_t index, node_t* node, void* data) {\n  return (!strcmp(node-\u003eelement, data));\n}\n\n// Remove from the list each node holding\n// the constant string 'foo'.\nlist_remove_node_if(list, predicate, \"foo\");\n```\n\n\u003e The complexity of a node removal is linear `O(n)`.\n\n## Retrieving the size of a list instance\n\nRetrieving the size of the list is a constant time operation `O(1)`, since the size is maintained across each insertions and removals. You can retrieve it as follow :\n\n```C\nsize_t size = list_get_size(list);\n```\n\nSimilarly, it is also possible to call `list_is_empty` if you'd like to know whether the given list is empty :\n\n```C\nint empty = list_is_empty(list)\n```\n\n## Clearing a list\n\nTo remove all the nodes contained in the list, you can call `list_clear`.\n\n```C\nlist_clear(list);\n```\n\n## Destroying an instance of a list\n\nSimilarly to creating a new instance of a list dynamically, to delete a dynamic instance of a list, you must call `list_destroy`. This will cause every node left in the list to be deleted, and the list itself to be destroyed.\n\n```C\nlist_destroy(list);\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhqarroum%2Fcircular-linked-list","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fhqarroum%2Fcircular-linked-list","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhqarroum%2Fcircular-linked-list/lists"}