双向链表的常见操作有链表节点的创建,有序插入,查找,排序,删除与释放,打印等,其精髓在于头指针的灵活使用,以及合理的链表遍历。以下程序为具体函数实现,main函数和头文件自行脑补吧。
#include <stdio.h>
#include <stdlib.h>#include "double_link.h"
//有序插入节点
//被double_link_create 函数调用
{
//如果传进来的头指针指向空,那么就让头指针指向传进来的p_new
if(head == NULL){//空链表head = p_new;
//前后指向都为空,表示此时链表中只有p_new一个节点
p_new->next = NULL;p_new->prep = NULL;
}
else{
//如果传进来的不是空链表,则通过遍历链表找到p_new的位置
STU *p_mov = head;
//while内的程序即为遍历链表的过程,满足不满足其中一个条件时停止循环
while((p_new->id >= p_mov->id) && (p_mov->next != NULL)){p_mov = p_mov->next;
}
//跳出循环的可能性分为以下两种
//第一种为遍历过程中找到了序号大于新节点的p_mov,此时把新节点插入在当前p_mov节点的前面,以保证按顺序插入
if(p_new->id < p_mov->id){p_new->next = p_mov;
p_mov->prep->next = p_new;
p_new->prep = p_mov->prep;
p_mov->prep = p_new;
}
else{
//第二种是找到最后一个节点还是没有找到比新节点序号大的,此时新节点插在最后
p_mov->next = p_new;p_new->prep = p_mov;
p_new->next = NULL;
}
}
//注意此时一定要返回头指针,便于后续利用头指针遍历链表
return head;}
//创建链表的函数
STU *double_link_create(void)
{
STU *head = NULL;
//头指针必须要在最后返回
STU *ptemp = NULL;
int n=0;
while(1){
//创建空间节点
ptemp = (STU*)malloc(sizeof(STU));
if(ptemp == NULL){
perror("malloc node");
break;
}
//向新建节点结构体输入数据
printf("please input id name score:\n");
scanf("%d %s %d",&ptemp->id,ptemp->name,&ptemp->score);
getchar();
//判断是否结束
if(strcmp(ptemp->name,"quit") == 0){
free(ptemp);
ptemp = NULL;
break;
}
//节点添加到链表
head = double_link_insert(head,ptemp);
}
return head;
}
void double_link_delete(STU **head, int id)
{
STU *p_mov = *head;
if(*head == NULL){
return;
}
while(p_mov->id != id && p_mov->next != NULL){
p_mov = p_mov->next;
}
//删除节点时遍历结果分一下几种可能
if(p_mov->id != id && p_mov->next == NULL){//没有找到ID对应的节点,直接返回printf("not found id\n");
return;
}
if(p_mov == *head){//找到头节点
if(p_mov->next){
p_mov->next->prep = NULL;
*head = p_mov->next;
}
else{
p_mov->prep->next = NULL;
}
}
else if(p_mov->id == id && p_mov->next != NULL){//找到中间节点
p_mov->prep->next = p_mov->next;
p_mov->next->prep = p_mov->prep;
}
else{//p_mov指向尾节点
p_mov->prep->next = NULL;
}
free(p_mov);//把删除掉的节点内存释放掉
}
STU * double_link_remove_first(STU *head)
{
STU *p = NULL;
if(head == NULL)
return NULL;
p = head;//p用来保存头节点,便于后面free掉删除的头节点
if(head->next != NULL)//如果头节点不是尾节点
head->next->prep = NULL;
head = head->next;
free(p);
return head;//这里说明一下,如果函数实参传进来的是头指针的地址,即二级指针,则不需要有返回值,因为通过指向指针1的指针2可以改变指针1的指向。
}
STU * double_link_free(STU *head)
{
while(head){
head = double_link_remove_first(head);
}
return head;
}
void double_link_print(STU *head)
{
STU *p_mov = head;
STU *p_save;
if(head == NULL){
return ;
}
while(p_mov != NULL){
printf("id:%d,name:%s,score:%d\n",p_mov->id,p_mov->name,p_mov->score);
p_save = p_mov;//保存最后一个节点,可用于倒序打印
p_mov = p_mov->next;
}
//p_mov == NULL;
printf("***********************\n");
//此为倒着打印的实现过程
while(p_save){printf("id:%d,name:%s,score:%d\n",p_save->id,p_save->name,p_save->score);
p_save = p_save->prep;
}