Note: The main purpose of this article is to record your learning process and facilitate your communication. For reprint, please indicate from:
Http://blog.csdn.net/ab198604
The cyclic linked list extends the concept of one-way linked list and two-way linked list. The cyclic linked list makes the operation of the linked list more flexible. This is because both the one-way and two-way linked lists have the head and end nodes of the linked list. If we think further:
1. The next link field of the End Node of the one-way linked list points to its header node -->Forming a one-way cyclic linked list
2. The next link field of the End Node of the two-way linked list points to its header node, and the prev link field of the header node points to its end node -->Forming a two-way circular linked list
No matter how it changes or expands its concepts, you can easily understand the essentials of a circular linked list by grasping the essence of its "linked list. The cyclic linked list does not have any obvious header and tail nodes, because any element on the linked list can be regarded as the header and tail nodes, which mainly depends on the actual application. The main basis for distinguishing whether a linked list is a circular linked list is to determine whether it contains a complete "ring", that is, it does not have a real tail node like a single-chain table or a two-way linked list.
This article mainly describes the one-way cyclic linked list. The image is as follows:
1. Structure and Interface Definition of one-way cyclic linked list
/* * clist.h * Author: zhm * date: 2013-01-04 */#ifndef CLIST_H_#define CLIST_H_#include <stdlib.h>/* define a structure for the element */typedef struct CListElmt_{ void *data; struct CListElmt_ *next;}CListElmt;
The above struct defines each node element of the one-way cyclic linked list, a data field and the next pointer field pointing to its subsequent nodes.
typedef struct CList_{ int size; int (*match)(const void *key1, const void *key2); void (*destroy)(void *data); CListElmt *head;}CList;
The above struct defines a one-way cyclic linked list structure to represent a complete one-way cyclic linked list.
/* public interface */void clist_init(CList *list, void (*destroy)(void *data));void clist_destroy(CList *list);int clist_ins_next(CList *list, CListElmt *element, const void *data);int clist_rem_next(CList *list, CListElmt *element, void **data);#define clist_size(list) ((list)->size)#define clist_head(list) ((list)->head)#define clist_data(element) ((element)->data)#define clist_next(element) ((element)->next)#endif
The code above defines some basic operations for one-way cyclic linked list, including the following operations:
1. Initialization of one-way cyclic linked list
2 destruction of one-way cyclic linked list
3 insert operation
4. Delete
5. A general macro-defined operation is used to quickly obtain the number of elements, header nodes, data fields, and next fields in the linked list.
II. Implementation of Interface Details of one-way cyclic linked list
1. Initialization of one-way cyclic linked list
This step is relatively simple. You can see the code.
/* * clist.c * Author: zhm * date: 2013-01-04 */#include <stdlib.h>#include <string.h>#include "clist.h"/* clist_init */void clist_init(CList *list, void (*destroy)(void *data)){ list->size = 0; list->head = NULL; list->destroy = destroy; return;}
It mainly initializes the structure of the clist one-way cyclic linked list.
2 destruction of one-way cyclic linked list
/* clist_destroy */void clist_destroy(CList *list){ void *data; while( clist_size(list) > 0 ) { if( clist_rem_next(list, list->head, (void **)&data) == 0 && list->destroy != NULL ) { //destroy the memory where the data point to. list->destroy(data); } } memset(list, 0, sizeof(CList)); return;}
The main idea of code implementation is to iterate each element in the linked list and remove it from the linked list, and call your own destroy function for the data field in each element to recycle memory resources.
3 insert operation
The Code is as follows:
/* clist_ins_next */int clist_ins_next(CList *list, CListElmt *element, const void *data){ CListElmt *new_element; /* allocate the memory */ new_element = (CListElmt *)malloc(sizeof(CListElmt)); if( new_element == NULL ) return -1; /* insert the new element into the list */ new_element->data = (void *)data; if( clist_size(list) == 0 ) { //when the list is empty. be care! new_element->next = new_element; //here, new_element is the head and the tail element; list->head = new_element; } else { //when the list is not empty. new_element->next = element->next; element->next = new_element; } /* Adjust the size */ list->size++; return 0;}
Note the following in the above Code:
(1) note that when the linked list is empty
(2) When the first element is inserted, It is a header node and its next pointer field points to itself to form a closed loop.
4. Delete
/* clist_rem_next */int clist_rem_next(CList *list, CListElmt *element, void **data){ CListElmt *old_element; //keep the element which to be removed. /* Do not remove from an empty list */ if( clist_size(list) == 0 ) return -1; /* Remove the element from the list */ *data = (void *)element->next->data; if( element->next == element ) //be care the condition. { /* when the element is the last element */ old_element = element; list->head = NULL; } else { /* remove the other element */ old_element = element->next; element->next = element->next->next; if( old_element == clist_head(list) ) //if the head element will be removed. list->head = old_element->next; } free(old_element); list->size--; return 0;}
The delete operation is also very simple. The overall idea is to get the data field of the elements to be deleted and adjust the next pointer field of the elements before and after the deleted elements. Note the following:
(1) because it is a circular linked list, when the deleted element is the header node, you need to maintain the head pointer field of the linked list.
(2) When the deleted element is the last element, you also need to maintain the head pointer field.
3. Simple application example of one-way cyclic linked list
The application code in this example is similar to the blog article "two-way linked list". The code is very simple. It is mainly used to apply the interface of one-way circular linked list and its macro-defined operations to complete the initialization of one-way circular linked list, insert, delete, and destroy elements. In this example, a struct is used to represent a cube. The struct maintains three variables: length, width, and height. The Code is as follows:
/* * main.c * author:zhm * date: 2013-01-04 */#include <stdio.h>#include <string.h>#include <stdlib.h>#include "clist.h"typedef struct Cuboid_{ int length; int width; int height;}Cuboid;
This struct represents some attributes of a cube. It serves only to let the data fields of elements in a one-way linked list represent a cube. Can refer to the "two-way linked list" the third part of the blog: http://blog.csdn.net/ab198604/article/details/8275020
Before assigning values to the data field of each element, You need to instantiate a rectangular object. The Code is as follows:
Cuboid *cube_instance(const int length, const int width, const int height){ Cuboid *cb_ptr; cb_ptr = (Cuboid *)malloc(sizeof(Cuboid)); if( cb_ptr == NULL ) return NULL; cb_ptr->length = length; cb_ptr->width = width; cb_ptr->height = height; return cb_ptr;}
The following is the content of the main function. The specific code is not described. It is very simple and you can understand it after reading it.
/* main */int main(int argc, char **argv){ int i; int ret = 0; CList clist; CListElmt *p = NULL; Cuboid *cb1_ptr, *cb2_ptr, *cb3_ptr, *cb4_ptr, *cb5_ptr; Cuboid *cb_ptr; //cb1_ptr ~ cb5_ptr are the data of the 5 elements. cb1_ptr = cube_instance(1,2,3); cb2_ptr = cube_instance(6,10,8); cb3_ptr = cube_instance(5,20,30); cb4_ptr = cube_instance(17,100,25); cb5_ptr = cube_instance(3,6,9); //init the clist clist_init(&clist, destroy); //insert the above 5 element /* cb1 -> cb1 */ ret = clist_ins_next(&clist, NULL, (void *)cb1_ptr); if( ret != 0 ) { printf("insert cb1 error\n"); return -1; } /* cb1 -> cb2 -> cb1 */ p = clist_head(&clist); ret = clist_ins_next(&clist, p, (void *)cb2_ptr); if( ret != 0 ) { printf("insert cb2 error\n"); return -1; } /* cb1 -> cb2 ->cb3 ->cb1*/ p = clist_next(p); ret = clist_ins_next(&clist, p, (void *)cb3_ptr); if( ret != 0 ) { printf("insert cb3 error\n"); return -1; } /* cb1 -> cb2 -> cb3 -> cb4 ->cb1 */ p = clist_next(p); ret = clist_ins_next(&clist, p, (void *)cb4_ptr); if( ret != 0 ) { printf("insert cb4 error\n"); return -1; } /* cb1 -> cb2 -> cb3 -> cb4 ->cb5 -> cb1 */ p = clist_next(p); ret = clist_ins_next(&clist, p, (void *)cb5_ptr); if( ret != 0 ) { printf("insert cb5 error\n"); return -1; } p = clist_head(&clist); //get the head element for(i = 0; i < clist_size(&clist) + 1; i++ ) { cb_ptr = (Cuboid *)clist_data(p); // get the element's data, every data is a Cuboid 's pointer. printf("i = %d: ",i); printf("length = %d, width = %d, height = %d\n", cb_ptr->length, cb_ptr->width, cb_ptr->height); p = clist_next(p); //pointer to next element. } //remove the head element clist_rem_next(&clist, p, (void **)&cb_ptr); printf("the removed element: length = %d, width = %d, height = %d\n", cb_ptr->length, cb_ptr->width, cb_ptr->height); destroy(cb_ptr); //free the memeory //destroy the circle list clist_destroy(&clist); printf("after destroy the list, its size = %d\n", clist_size(&clist)); return 0;}
The main logic of the above Code is: first instantiate five cubes, then initialize a one-way circular linked list, and then insert the five cubes into the linked list as data fields, then, an element is deleted, and the entire circular linked list is destroyed. After compilation, run the program and the results are as follows:
Note: If you have any need, you can leave a mailbox. If you have time, I will send you the complete debugging code via email.