先写头文件dlist.h
#pragma once
//双向链表结构体设计:
typedef int ELEM_TYPE;
typedef struct Dlist
{
ELEM_TYPE data;//数据域 保存有效值
struct Dlist* next;//指针域 保存下一个节点的地址(后继)
struct Dlist* prior;//指针域 保存上一个节点的地址(前驱)
}Dlist, *PDlist;
//双向链表可执行函数声明:
//初始化
void Init_dlist(struct Dlist* plist);
//购买新节点
struct Dlist* BuyNode(ELEM_TYPE val);
//头插
bool Insert_head(PDlist plist, ELEM_TYPE val);
//尾插
bool Insert_tail(PDlist plist, ELEM_TYPE val);
//按位置插
bool Insert_pos(PDlist plist, int pos, ELEM_TYPE val);
//头删
bool Del_head(PDlist plist);
//尾删
bool Del_tail(PDlist plist);
//按位置删
bool Del_pos(PDlist plist, int pos);
//按值删除
bool Del_val(PDlist plist, ELEM_TYPE val);
//查找(如果值重复,返回第一次出现的节点地址)
struct Dlist* Search(PDlist plist, ELEM_TYPE val);
//判空
bool IsEmpty(PDlist plist);
//判满(链表不用实现)
//获取有效长度
int Get_length(PDlist plist);
//清空
void Clear(PDlist plist);
//销毁1
void Destroy(PDlist plist);
//销毁2
void Destroy2(PDlist plist);
//打印
void Show(PDlist plist);
再写dlist.cpp文件
#include#include #include #include "dlist.h" //初始化(排除两个野指针的风险,将其全部赋值为NULL) void Init_dlist(struct Dlist* plist) { //assert plist->next = plist->prior = NULL; } //购买新节点(一次购买一个) struct Dlist* BuyNode(ELEM_TYPE val) { //assert struct Dlist* pnewnode = (struct Dlist*)malloc(1 * sizeof(struct Dlist)); assert(pnewnode != NULL); if(NULL == pnewnode) { return NULL; //购买失败 } pnewnode->data = val; pnewnode->next = pnewnode->prior = NULL; return pnewnode; } //头插 bool Insert_head(PDlist plist, ELEM_TYPE val) { //assert plist //1.购买新节点 struct Dlist* pnewnode = (struct Dlist*)malloc(1 * sizeof(struct Dlist)); assert(pnewnode != NULL); pnewnode->data = val; pnewnode->next = NULL; pnewnode->prior = NULL; //2.找个合适的插入位置(找一个指针指向插入位置的上一个节点) //头插不用找(因为plist就指向插入位置的上一个节点) //3.插入 (3421) //第一次:自身的两条线 //第二次:再修改后一个节点的前驱 //第三次:最后修改上一个节点的后继 pnewnode->next = plist->next;//3 pnewnode->prior = plist;//4 if(plist->next != NULL) { plist->next->prior = pnewnode;//2 } plist->next = pnewnode;//1 return true; } //尾插(尾插的话,下一个节点肯定不存在,所以下一个节点的前驱这根线,不用写) bool Insert_tail(PDlist plist, ELEM_TYPE val) { //assert struct Dlist* pnewnode = (struct Dlist*)malloc(1 * sizeof(struct Dlist)); assert(pnewnode != NULL); pnewnode->data = val; pnewnode->next = NULL; pnewnode->prior = NULL; //2.找个合适的插入位置(找一个指针p指向尾结点) struct Dlist* p=plist; for( ; p->next!=NULL; p=p->next); //此时 for循环结束 p指向尾结点 //3.插入 (3421) pnewnode->next = p->next; //3 pnewnode->prior = p;//4 //2 这个2不用写,因为尾插不存在 更后边的节点 p->next = pnewnode; return true; } 按位置插(pos=0 相当于头插, pos==length 相当于尾插) //bool Insert_pos1(PDlist plist, int pos, ELEM_TYPE val) //{ // assert(plist != NULL); // assert(pos>=0 && pos<=Get_length(plist)); // // // //1.购买新节点 // struct Dlist* pnewnode = (struct Dlist*)malloc(1 * sizeof(struct Dlist)); // assert(pnewnode != NULL); // pnewnode->data = val; // pnewnode->next = NULL; // pnewnode->prior = NULL; // // //2.找个合适的插入位置(找一个指针p指向待插入位置的上一个节点) // struct Dlist* p=plist; // for(int i=0; i next; // } // //此时 for循环结束 p指向待插入位置的上一个节点 // // //3.插入 (3421) // pnewnode->next = p->next;//3 // pnewnode->prior = p;//4 // if(pos != Get_length(plist) && !IsEmpty(plist)) // { // p->next->prior = pnewnode;//pnewnode->next->prior = pnewnode;//2 // } // p->next = pnewnode;//1 // // return true; //} //按位置插(pos=0 相当于头插, pos==length 相当于尾插) bool Insert_pos(PDlist plist, int pos, ELEM_TYPE val) { assert(plist != NULL); assert(pos>=0 && pos<=Get_length(plist)); //头部和尾部有风险, 那最开始就排除掉 if(pos == 0) { return Insert_head(plist, val); } else if(pos == Get_length(plist)) { return Insert_tail(plist, val); } //此时,能执行到这里,代表头部和尾部风险全部排除掉,剩余情况就普遍情况了(4根线都存在) //1.购买新节点 struct Dlist* pnewnode = (struct Dlist*)malloc(1 * sizeof(struct Dlist)); assert(pnewnode != NULL); pnewnode->data = val; pnewnode->next = NULL; pnewnode->prior = NULL; //2.找个合适的插入位置(找一个指针p指向待插入位置的上一个节点) struct Dlist* p=plist; for(int i=0; i next; } //此时 for循环结束 p指向待插入位置的上一个节点 //3.插入 (3421) pnewnode->next = p->next;//3 pnewnode->prior = p;//4 p->next->prior = pnewnode;//pnewnode->next->prior = pnewnode;//2 p->next = pnewnode;//1 return true; } //头删 bool Del_head(PDlist plist) { //assert //插入不需要判满 但是删除一定记得判空 if(IsEmpty(plist)) { return false; } //找个指针p指向待删除节点 struct Dlist *p =plist->next; //找个指针q指向待删除节点的上一个节点(此时plist替代了指针q的作用) //跨越指向+释放内存 plist->next = p->next;//plist->next = plist->next->next; if(p->next != NULL)//代表 不仅仅只有一个有效值 { p->next->prior = plist; } free(p); return true; } //尾删 bool Del_tail(PDlist plist) { //assert if(IsEmpty(plist))//插入不需要判满 但是删除一定记得判空 { return false; } //第二种策略 先找q 再找p struct Dlist *q = plist; for(q; q->next->next!=NULL; q=q->next); //此时 for循环结束 q指向倒数第二个节点 struct Dlist *p = q->next; //跨越指向+释放内存 q->next = p->next;//让上一个节点指向下一个节点 //让下一个节点指向上一个节点(因为是尾删,所以待删除节点后面没有节点了) free(p); return true; } //按位置删(一般来说,头和尾比较危险,一开始处理掉即可) bool Del_pos(PDlist plist, int pos) { assert(plist != NULL); assert(pos >=0 && pos next; } struct Dlist *p = q->next; q->next = p->next; p->next->prior = q; free(p); return true; } //按值删除(特殊情况:如果你找的val值 在尾结点找到了) bool Del_val(PDlist plist, ELEM_TYPE val) { //assert if(IsEmpty(plist))//插入不需要判满 但是删除一定记得判空 { return false; } struct Dlist* p = Search(plist, val); if(p == NULL) { return false; } //在申请一个指针q,指向p的前一个节点 struct Dlist *q = plist; for(q; q->next!=p; q=q->next); //此时 q在p前面 //跨越指向 + 释放内存 q->next = p->next; //ok if(p->next != NULL) { p->next->prior = q;//特殊情况:如果你找的val值 在尾结点找到了 这行代码就会失败 } free(p); return true; } //查找(如果值重复,返回第一次出现的节点地址) struct Dlist* Search(PDlist plist, ELEM_TYPE val) { //assert for(struct Dlist* p=plist->next; p!=NULL; p=p->next) { if(p->data == val) { return p; } } return NULL; } //判空 bool IsEmpty(PDlist plist) { return plist->next == NULL; } //判满(链表不用实现) //获取有效长度 int Get_length(PDlist plist) { int count = 0; for(struct Dlist* p=plist->next; p!=NULL; p=p->next) { count++; } return count; } //清空 void Clear(PDlist plist) { Destroy(plist); } //销毁1(借助头结点,无限头删) void Destroy(PDlist plist) { //assert while(plist->next != NULL) { struct Dlist *p = plist->next; plist->next = p->next;//这里只需要上一个节点 指向下一个节点即可 free(p); } plist->next = plist->prior = NULL; } //销毁2(不借助头结点, 但是有两个临时指针变量) void Destroy2(PDlist plist) { //assert struct Dlist *p = plist->next; struct Dlist *q = NULL; plist->next = plist->prior = NULL; while (p != NULL) { q = p->next; free(p); p = q; } } //打印 void Show(PDlist plist) { //assert for(struct Dlist* p=plist->next; p!=NULL; p=p->next) { printf("%d ", p->data); } printf("n"); }
最后在主函数中实现代码
#include#include "assert.h" #include #include //#include "sqlist.h" //#include "Dsqlist.h" //#include "list.h" //#include "no_head_list.h" #include "dlist.h" int main() { struct Dlist head; Init_dlist(&head); for(int i=0; i<20; i++) { Insert_pos(&head, i, i+1); } Show(&head); Insert_head(&head, 100); Insert_tail(&head, 200); Show(&head); printf("length = %dn", Get_length(&head)); Del_head(&head); Del_tail(&head); Show(&head); printf("length = %dn", Get_length(&head)); Del_pos(&head, 3); Del_val(&head, 14); Show(&head); printf("length = %dn", Get_length(&head)); //Destroy(&head); Destroy2(&head); return 0; }



