Note: The main purpose of this article is to record their own learning process, but also convenient to communicate with you. Reprint please specify from:
http://blog.csdn.net/ab198604
In the previous summary of the one-way linked list structure, now began to practice the two-way linked list structure, if fully understand the data structure of unidirectional linked list, the structure of the two-way linked list is no longer difficult to understand, in other words, doubly linked list is one-way linked list expansion, if from the definition of data structure code to see, Two-way lists need to maintain three data content: data, the front pointer (prev), and the back pointer (next). Compared to the one-way linked list structure, it is necessary to maintain a prev pointer field in the program code, as shown in the following diagram:
The benefits of this are:
The 1 traversal of the linked list data can be traversed not only backwards (such as a single-linked list), but can also be traversed forward to find the element, and the operation of the linked list data is more flexible.
2 can delete a data element directly, I think this is a more important aspect, because for a single-linked list, if you want to delete a data element, you need to traverse a node before this element can be deleted, and the doubly linked list can traverse to an element, and then can directly delete it.
Similar to the one-way list, this content also mainly from the following three aspects to discuss the design of two-way linked list:
one, two-way linked list structure and interface definition
/
* * filename:dlist.h
* AUTHOR:ZHM * date:2012-12-08 */
#ifndef _dlist_h
#define _dlist_h
#include <stdlib.h>/
* Define a structure for the list element*/
typedef struct DLISTELMT_
{
void *data;
struct Dlistelmt_ *prev;
struct dlistelmt_ *next;
} DLISTELMT;
The above structure defines each of the elements that a doubly linked list needs to maintain, each containing three items, and in addition to defining a struct to maintain the entire list, the code looks like this:
/* Define a structure for the double linked list */
typedef struct DLIST_
{
int size;
void (*destroy) (void *data);
void (*match) (const void *key1, const void *key2);
DLISTELMT *head;
DLISTELMT *tail;
} Dlist;
The data management and maintenance of the two-way linked list mainly has the above content, which contains the number of list elements (size), the destruction of the list of function pointers (destroy), head, tail linked list element pointers. In addition to this, you need to define the related operation interfaces and macro definitions associated with the linked list, as shown in the following code:
/* define public interface */void Dlist_init (Dlist *list, Void (*destroy) (void *data)); void Dlist_destr
Oy (Dlist *list);
int Dlist_ins_prev (dlist *list, dlistelmt *element, const void *data);
int Dlist_ins_next (dlist *list, dlistelmt *element, const void *data);
int Dlist_remove (dlist *list, DLISTELMT *element, void **data);
#define DLIST_SIZE (list)->size//get the size of the list. #define DLIST_HEAD (list)->head//get the head element #define DLIST_TAIL (list)->tail the Tai L element #define Dlist_is_head (element)->prev = = NULL? 1:0)//whether The element is head or not #define Dlist_is_tail (Element) (element)->next = = NULL? 1:0)//whether the element is tail or not #define DLIST_DATA (eleme NT) (Element)->data)//get the data of the element #define DLIST_PREV (Element)->prev)//get the prev ele ment #define DLIST_NEXT (Element)->next//get the next element #endif
In general, as with single-linked lists, the operations associated with a doubly linked list are:
(1) The initialization of the doubly linked list;
(2) The destruction of the doubly linked list;
(3) Insert element operation for doubly linked list: forward insertion and back insertion
(4) The deletion of two-way linked list elements;
(5) Related macro definitions, mainly for the convenience of code maintenance and operation.
two, two-way linked list interface operation details implementation
1 Initialization of a doubly linked list.
/
* * filename:dlist.c * AUTHOR:ZHM * date:2012-12-08 * * * *
#include <stdlib.h>
#include <string.h>
#include "dlist.h"/
* dlist_init *
/void Dlist_init (Dlist *list, Void (*destroy) (void * Data)
{
list->size = 0;
List->destroy = Destroy;
List->head = NULL;
List->tail = NULL;
return;
}
It is relatively simple to assign the initial value to the contents of a doubly linked list structure.
2 destruction of doubly linked lists
/* Dlist_destroy *
/void Dlist_destroy (Dlist *list)
{
void *data;
while (Dlist_size (list) > 0)
{
if (Dlist_remove (list, Dlist_tail (list), (void * *) &data) = = 0//from the H EAD to destroy
&& List->destroy! = NULL)
{
List->destroy (data);}
}
memset (list, 0, sizeof (dlist));
return;
}
It is important to note that this function calls the element delete function of the doubly linked list, removes each element through an outer loop iteration, and eventually changes the size of the entire list to 0, exiting the iteration. After you delete each element, you also need to release the space occupied by the data field within the element. The element removal function implementation Details (DLIST_REMOVE) for the doubly linked list are described later.
3 Insert element operation for doubly linked list (forward insertion)
/* Dlist_ins_prev */int Dlist_ins_prev (dlist *list, dlistelmt *element, const void *data) {DLISTELMT *new_element; Do not allow a null unless the list is empty if (element = = NULL && dlist_size (list)! = 0) Retu
rn-1;
New_element = (DLISTELMT *) malloc (sizeof (DLISTELMT));
if (new_element = = NULL) return-1;
New_element->data = (void *) data;
if (dlist_size (list) = = 0) {list->head = new_element;
List->tail = new_element;
New_element->prev = NULL;
New_element->next = NULL;
} else {new_element->next = element;
New_element->prev = element->prev;
if (Element->prev = = NULL) {list->head = new_element;
} else {element->prev->next = new_element;
} Element->prev = New_element;
}/* Adjust the size */list->size++; return 0; }
The so-called forward insertion, as the name implies, is the insertion of a new element from the front of an element node in a doubly linked list, which has three parameters, the element represents the location of the reference node to be inserted, and it is important to note that:
If element = null, the doubly linked list should be empty, or exit and return 1;
if element! = is NULL, you need to insert elements in the Element->prev location, and the data field for the new element to be inserted is the third parameter. It is also necessary to consider what happens when element is the head node .
4 Insert element operation for doubly linked list (back insert)
/* Dlist_ins_next */int Dlist_ins_next (dlist *list, dlistelmt *element, const void *data) {DLISTELMT *new_element; Do not allow a null unless the list is empty if (element = = NULL && dlist_size (list)! = 0) ret
urn-1;
Allocate the memory for the new element.
New_element = (DLISTELMT *) malloc (sizeof (DLISTELMT));
if (new_element = = NULL) return-1;
Fill the data to the element new_element->data = (void *) data; Insert the element to the list if (dlist_size (list) = = 0) {//the list is empty New_element->
;p rev = NULL;
New_element->next = NULL;
List->head = new_element;
List->tail = new_element; } else {//the list is not empty if (dlist_next (element) = = NULL) {list->
tail = new_element;
} else {new_element->next->prev = new_element; } new_elemenT->next = element->next;
New_element->prev = element;
Element->next = new_element;
}//adjust the size list->size++;
return 0; }
A back-to-insert is similar to a forward insertion, but unlike the forward direction, it is important to consider that when inserting a reference node as tail, such as if (dlist_next (element) = = NULL) in the previous code, this is mostly a matter of detail and is easily overlooked. After the insert is complete, you need to accumulate the size of the linked list elements.
5 Deletion of doubly linked list elements
Well, keep looking at the code. ~~
/* dlist_remove */int Dlist_remove (dlist *list, DLISTELMT *element, void **data) {//do not allow a
Null or a empty list if (element = = NULL | | dlist_size (list) = = 0) return-1;
/* Remove the element from the list */*data = element->data;
if (element = = List->head) {List->head = element->next;
if (List->head = = null) {list->tail = null;
} else {element->next->prev = NULL;
}} else {element->prev->next = element->next;
if (Element->next = = NULL)//be Care of the last element;
{List->tail = element->prev;
} else {Element->next->prev = element->prev;
}}/* Free the Sotrage */free (element);
/* Adjust the size */list->size--;
return 0; }
Note that the third parameter, which holds the data field in the deleted element, is saved because the data field is designed to be self-maintained by the user at the time of use, and the user allocates and frees the space themselves when needed, a design that is more flexible and versatile. The second parameter element determines the elements that need to be deleted, that is, the elemental itself, provided that the doubly linked list cannot be empty. And you need to release the element node space and resize the element when you're done deleting it. It is also important to consider the need to maintain the head and tail of the doubly linked list when the deleted node is a header and tail node.
three, two-way chain List application Example
This application is relatively simple, the main purpose is to apply the bidirectional list of each interface operation and macro definition content. Know how to use a doubly linked list. In this example, the box is represented by a struct, containing three variables, length, width, and height, respectively, as follows:
/
* * FILENAME:MAIN.C * AUTHOR:ZHM * date:2012-12-08 * * * *
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "dlist.h"
typedef struct CUBOID_
{
int length;
int width;
int height;
} Cuboid;
The variables produced by this data type are used as data data fields for the two-way linked list element. Before assigning a value to the data field of each element, the following instantiation function is called to produce a data object of each cuboid type and return its pointer, as shown in the following code:
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 above function uses the scene as shown below to intercept part of the code from the main function.
/* main *
/int main (int argc, char **argv)
{
int i;
Dlist Dlist_exp;
DLISTELMT *p = NULL;
Cuboid *cb1_ptr, *cb2_ptr, *cb3_ptr, *cb4_ptr, *cb5_ptr;
Cuboid *cb_ptr;
Cb1_ptr ~ cb5_ptr is the data of the 5 elements.
Cb1_ptr = Cube_instance (n/a);
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);
......
}
As the above code produces five box objects by calling the Cube_instance () function, and each object has its own length-width-height value, each object is maintained with the box pointer cuboid *. Here we initialize the Dlist_exp doubly linked list, then insert 5 elements, each of which will be given a pointer to the box object. The code looks like this:
int main (int argc, char **argv) {...//init the double linked list.
Dlist_init (&dlist_exp, destroy); Insert the 5 elements into the dlist dlist_ins_next (&dlist_exp, NULL, (void *) cb1_ptr); Insert DATA:CB1 p = dlist_head (&DLIST_EXP); Get the address of the first element Dlist_ins_next (&dlist_exp, p, (void *) cb2_ptr); Insert DATA:CB2 CB1-CB2 p = dlist_next (p);
Pointer to the element containing the data cb2. Dlist_ins_prev (&dlist_exp, p, (void *) cb3_ptr); Insert Data:cb3 cb1-cb3-cb2 dlist_ins_prev (&dlist_exp, p, (void *) cb4_ptr); Insert DATA:CB4 CB1-CB3-CB4-CB2 p = Dlist_prev (p);
Pointer to the element conatining the data cb4. Dlist_ins_prev (&dlist_exp, p, (void *) cb5_ptr); Insert Data:cb5 cb1-cb3-cb5-cb4-cb2 ...}
Notice the order of the inserts (forward and back inserts, which already indicate the order of the post-insert list, which is no longer described here.) We will show the list traversal output after the insert is completed, and display the data field value for each element, with the following code:
Now the sequence is:head->cb1->cb3->cb5->cb4->cb2
printf ("Traverse and print:\n");
p = dlist_head (&DLIST_EXP); Get the head element;
for (i = 0; i < dlist_size (&dlist_exp); i++)
{
cb_ptr = (Cuboid *) Dlist_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 = dlist_next (p);//pointer to next element;
}
In order to demonstrate the element node operation in the delete list, it is intended to delete the element of the 3rd node, which is the element containing the data cb5 (3,6,9) box, and then iterate over the value of the field that displays each element, following the code:
//we ' ll remove the third Element:that ' s containing the data of CB5 (3,6,9) p = dlist_head (&dli
ST_EXP);
p = Dlist_next (p);
p = Dlist_next (p);
Dlist_remove (&dlist_exp, p, (void * *) &cb_ptr);
printf ("The data of the third Element:length =%d, width =%d, height =%d\n", Cb_ptr->length,
Cb_ptr->width, Cb_ptr->height); Destroy (CB_PTR);
Free the memory//now we'll show you the remained elements,the sequence is:(head) CB1->CB3->CB4->CB2 (tail)
printf ("After remove the third elements:\n");
p = dlist_head (&DLIST_EXP);
for (i = 0; i < dlist_size (&dlist_exp); i++) {cb_ptr = (Cuboid *) Dlist_data (p);
printf ("I =%d:", i);
printf ("Length =%d, Width =%d, height =%d\n", Cb_ptr->length, Cb_ptr->width,
Cb_ptr->height);
p = Dlist_next (p); }
The above code is simple and is no longer explained here. The last is to destroy the list operation, the code is as follows:
......
Destroy the double linked list
Dlist_destroy (&dlist_exp);
printf ("After destroy the list,its size =%d\n", Dlist_size (&dlist_exp));
......
Finally, I will main.c source code throughout the show, the need for friends can do their own run, deepen the impression, MAIN.C source as follows:
/* * FILENAME:MAIN.C * AUTHOR:ZHM * date:2012-12-08 * * * #include <stdio.h> #include <stdlib.h> #include <s
tring.h> #include "dlist.h" typedef struct CUBOID_ {int length;
int width;
int height;
}cuboid;
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;
}/*destroy */void Destroy (void *data) {free (data);
Return
}/* main */int main (int argc, char **argv) {int i;
Dlist Dlist_exp;
DLISTELMT *p = NULL;
Cuboid *cb1_ptr, *cb2_ptr, *cb3_ptr, *cb4_ptr, *cb5_ptr;
Cuboid *cb_ptr;
Cb1_ptr ~ cb5_ptr is the data of the 5 elements.
Cb1_ptr = Cube_instance (n/a);
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 double linked list.
Dlist_init (&dlist_exp, destroy); Insert the 5 elements into the dlist dlist_ins_next (&dlist_exp, NULL, (void *) cb1_ptr); Insert DATA:CB1 p = dlist_head (&DLIST_EXP); Get the address of the first element Dlist_ins_next (&dlist_exp, p, (void *) cb2_ptr); Insert DATA:CB2 CB1-CB2 p = dlist_next (p);
Pointer to the element containing the data cb2. Dlist_ins_prev (&dlist_exp, p, (void *) cb3_ptr); Insert Data:cb3 cb1-cb3-cb2 dlist_ins_prev (&dlist_exp, p, (void *) cb4_ptr); Insert DATA:CB4 CB1-CB3-CB4-CB2 p = Dlist_prev (p);
Pointer to the element conatining the data cb4. Dlist_ins_prev (&dlist_exp, p, (void *) cb5_ptr); Insert DATA:CB5 cb1-cb3-cb5-cb4-cb2//now the sequence IS:HEAD->CB1->CB3->CB5->CB4->CB2 p
rintf ("Traverse and print:\n"); p = Dlist_heaD (&DLIST_EXP);
Get the head element; for (i = 0; i < dlist_size (&dlist_exp); i++) {cb_ptr = (Cuboid *) Dlist_data (p);//get the element ' s D
ATA, 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 = Dlist_next (p);
Pointer to next element;
}//we ' ll remove the third Element:that ' s containing the data of CB5 (3,6,9) p = dlist_head (&DLIST_EXP);
p = Dlist_next (p);
p = Dlist_next (p);
Dlist_remove (&dlist_exp, p, (void * *) &cb_ptr);
printf ("The data of the third Element:length =%d, width =%d, height =%d\n", Cb_ptr->length,
Cb_ptr->width, Cb_ptr->height); Destroy (CB_PTR); Free the memory//now we'll show you the remained elements,the sequence is:(head) CB1->CB3->CB4->CB2 (tail)
printf ("After remove the third elements:\n");
p = dlist_head (&DLIST_EXP);
for (i = 0; i < dlist_size (&dlist_exp); i++) {cb_ptr = (Cuboid *) Dlist_data (p);
printf ("I =%d:", i);
printf ("Length =%d, Width =%d, height =%d\n", Cb_ptr->length, Cb_ptr->width,
Cb_ptr->height);
p = Dlist_next (p);
}//destroy the double linked list Dlist_destroy (&DLIST_EXP);
printf ("After destroy the list,its size =%d\n", Dlist_size (&dlist_exp));
return 0;
}
After compiling, the execution results of the program are as follows: