3.2、双链表

一、循环链表
循环链表中第一个节点之前就是最后一个节点,反之亦然。循环链表的无边界使得在这样的链表上设计算法会比普通链表更加容易。

二、有头循环双链表
双向链表中不仅有指向后一个节点的指针,还有指向前一个节点的指针。起始的时候第一个节点的”前连接”指向自己,”后连接”指向自己;非空的时候第一个节点的”前连接”指向自己最后一个节点,最后一个节点的”后连接”指向第一个节点。
这样可以从任何一个节点访问前一个节点,也可以访问后一个节点,以至整个链表。一般是在需要大批量的另外储存数据在链表中的位置的时候用。

typedef struct SList{
     DataType data;
     struct SList* pPrev;
     struct SList* pNext;
}SList;

1、空链表 — 有一个头,并非什么都没有
在这里插入图片描述
2、非空链表
在这里插入图片描述
在这里插入图片描述
三、头、尾插法
在这里插入图片描述
在这里插入图片描述
四、新增数据–代码示例
参数:结构体指针,新增方式,数据大小,新增数据

#define HEAD_INSERT		0
#define TRAIL_INSERT	1

int doulist_insert(doulist_t *head,const data_t *data,int size,int mode){
    doulist_t *new = NULL;
    
    new = malloc(sizeof(*new));   //开辟一个新的节点
    if(data == NULL)
        return -1;
        
    if(mode != 0 && mode != 1)
        return -2;
        
    if(size <= 0)
        return -3;
        
    if(new == NULL)
        return -4;
        
    new -> data = malloc(size);   //为数据开辟一块空间
    if(new -> data == NULL){
        free(new);
        return -5;    
    }    
    memcpy(new -> data,data,size);//是void * 类型不能取值,内存拷贝
    
    switch(mode){
        case HEAD_INSERT:   //头 HEAD_INSERT
            new -> next = head -> next; 
            new -> prev = head;
            head -> next = new;
            new -> next -> prev = new;
            break;
        case TRAIL_INSERT: //尾  TRAIL_INSERT
            new -> next = head;
            new -> prev = head -> prev;
            head -> prev = new;
            new -> prev -> next = new;
            break;
    }
    return 0;
}

五、双链表删除
在这里插入图片描述
六、双链表删除 – 代码示例

//删除数据
int doulist_delete(doulist_t *head,const data_t *data,int size){
    doulist_t *pos = NULL;
    if(data == NULL) return -1;
    if(size <= 0) return -2;
    
    for(pos = head -> next; pos != head ;pos = pos -> next)
        if(memcmp(pos -> data,data,size) == 0){  //如果节点的数据跟要删除的数据内存对比相等
            pos -> prev -> next = pos -> next;
            pos -> next -> prev = pos -> prev;
            free(pos -> data);
            pos -> data = NULL;
            free(pos);
            pos = NULL;
            return 0;
        }
    return -3;
}

七、释放链表
在这里插入图片描述
在这里插入图片描述

八、释放链表 – 代码示例

//释放链表空间,成功返回0
int doulist_destroy(doulist_t *head){    
	doulist_t *pos = NULL;    
	doulist_t *last =  head -> prev;  //记录最后一个节点   
	
	//从第一个节点开始释放上一个节点
	for(pos = head -> next;pos != head;pos = pos -> next){            
		if(pos -> prev -> data != NULL){  //释放上一个数据空间              
			free(pos -> prev -> data);                
			pos -> prev -> data = NULL;            
		}     
		           
		free(pos -> prev);         //释放上一个节点   
		pos -> prev = NULL;        
	}  
	 
	//释放最后一个节点 
	if(last -> data != NULL){        
		free(last -> data);        
		last -> data = NULL;   
	}    
	
	free(last);    
	last = NULL;    
	return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_41110647/article/details/106327027