赞
踩
0.在开始之前建议先跟着思路,走一遍,调试部分我就不放了主要写的是实现思路。当然最后也会把源码附上。
- typedef int LTDataType;
- typedef struct ListNode
- {
- struct ListNode* next; //指针保存下⼀个节点的地址
- struct ListNode* prev; //指针保存前⼀个节点的地
- LTDataType data;
- }LTNode;
就比如尾插时不用对头指针改变,而头插就需要对头指针改变了
- typedef int DLDataType;
- typedef struct ListNode
- {
- DLDataType data;
- struct ListNode* prev;//指向上一个节点
- struct ListNode* next;//指向下一个节点
- }DLNode;//链表节点
- //第二种初始化方法为了保证接口的一致性,让传递的值都是一级指针
- DLNode* DLInit()
- {
- DLNode* node = DLBuyNode(-1);
- return node;
- }
-
- DLNode* DLInit()
- {
- DLNode* node = DLBuyNode(-1);
- return node;
- }
- //test.c 通过接收返回值的方式
- void DListTest1()
- {
- DLNode* plist = NULL;//哨兵位
- plist = DLInit();
- }
- //新空间
- DLNode* DLBuyNode(DLDataType x)
- {
- DLNode* newnode = (DLNode*)malloc(sizeof(DLNode));
- if (newnode == NULL)
- {
- perror("malloc nwe");
- exit(-1);//推出整个程序
- }
- newnode->data = x;
- newnode->next = newnode->prev = newnode;//申请新节点,需要自循环
- return newnode;
- }
- void DLPushBack(DLNode* phead, DLDataType x)
- {
- assert(phead);
- DLNode* newnode = DLBuyNode(x);
- //phead phead->prev newnode
- newnode->prev = phead->prev;//phead->prev 是头节点指向的上一个节点也就是尾节点
- newnode->next = phead;
-
- phead->prev->next = newnode;//尾节点指向的下一个节点
- phead->prev = newnode;
- }
- //新空间
- DLNode* DLBuyNode(DLDataType x)
- {
- DLNode* newnode = (DLNode*)malloc(sizeof(DLNode));
- if (newnode == NULL)
- {
- perror("malloc nwe");
- exit(-1);//推出整个程序
- }
- newnode->data = x;
- newnode->next = newnode->prev = newnode;//申请新节点,需要自循环
- return newnode;
- }
这张图是什么意思呢?意思是在头节点左边插入其实也是尾插,你可以想象一下,把链表想成环形
- void DLPrint(DLNode* phead)
- {
- DLNode* pcur = phead->next;//头节点指向下一个节点,也就是第一个有效节点
- while (pcur != phead)
- {
- printf("%d->", pcur->data);
- pcur = pcur->next;//遍历指向下一个节点
- }
- printf("\n");
- }
- void DLPushFront(DLNode* phead,DLDataType x)
- {
- assert(phead);//头节点不能为NULL
- DLNode* newnode = DLBuyNode(x);
- newnode->next = phead->next;
- newnode->prev = phead;
-
- //方法1
- //phead->next->prev = newnode;//第一个有效节点指向newnode
- //phead->next = newnode;//指向下一个节点
-
- //方法2
- phead->next = newnode;
- newnode->next->prev = newnode;
- }
- void DLDelBack(DLNode* phead)
- {
- //当phead->next != phead就正常执行
- assert(phead && phead->next != phead);//链表都为NULL你删什么?,如果是只剩一个头结点当然也不行
- DLNode* del = phead->prev;
- del->prev->next = phead;//删除的前一个节点指向phead
- phead->prev = del->prev;//头结点的前一个节点指向del->prev
- free(del);
- del = NULL;
- }
- void DLDelFront(DLNode* phead)
- {
- assert(phead && phead->next != phead);//如果保错就说明,要么为NULL,要么只有一个头结点
- DLNode* del = phead->next;//第一个有效节点
- phead->next = del->next;
- del->next->prev = phead;
- free(del);
- del = NULL;
- }
- //查找
- DLNode* DLFind(DLNode* phead, DLDataType x)
- {
- assert(phead);
- DLNode* pcur = phead->next;//可能存在多次查找,其次记得是第一个有效节点
- while (pcur != phead)
- {
- if (pcur->data == x)
- {
- return pcur;
- }
- pcur = pcur->next;
- }
- return NULL;
- }
- //test.c部分
- DLNode* find = DLFind(plist, 22);
- if (find == NULL)
- printf("没找到");
- else
- printf("找到了");
- //在指定位置插入
- void DLInsert(DLNode* pos, DLDataType x)
- {
- assert(pos);//防止phead == NULL链表
- DLNode* newnode = DLBuyNode(x);
- //pos newnode pos->next
- newnode->next = pos->next;
- newnode->prev = pos;
- // 2,3点
- pos->next->prev = newnode;
- pos->next = newnode;
- }
- //在指定位置删除
- void DLErase(DLNode* pos)
- {
- assert(pos);//可能会缺少phead的检查
- //pos->prev pos pos->next
- pos->next->prev = pos->prev;
- pos->prev->next = pos->next;
- free(pos);//pos置为NULL并不影响find
- pos = NULL;
- }
- //新空间
- DLNode* DLBuyNode(DLDataType x)
- {
- DLNode* newnode = (DLNode*)malloc(sizeof(DLNode));
- if (newnode == NULL)
- {
- perror("malloc nwe");
- exit(-1);//推出整个程序
- }
- newnode->data = x;
- newnode->next = newnode->prev = newnode;//申请新节点,需要自循环
- return newnode;
- }
- //第一种,双链表的初始化
- //void DLInit(DLNode** pphead)//只传参不返回值,因为可以对实参直接改变
- //{
- // *pphead = DLBuyNode(-1);
- //}
-
- //第二种初始化方法为了保证接口的一致性,让传递的值都是一级指针
- DLNode* DLInit()
- {
- DLNode* node = DLBuyNode(-1);
- return node;
- }
- void DListTest1()
- {
- //第一种
- //DLNode* plist = NULL;//哨兵位
- //DLInit(&plist);//对头节点改变需要二级指针
-
- //第二种初始化方式
- DLNode* plist = DLInit();
- }
- //销毁链表
- void DLDesTroy(DLNode* phead)
- {
- assert(phead);//此时链表可以为NULL
- DLNode* pcur = phead->next;
- while (pcur != phead)
- {
- DLNode* node = pcur->next;//保存后一个节点
- free(pcur);
- pcur = node;//把后一个节点给到pcur
- }
- free(phead);
- phead = NULL;//两个名字都有访问这块空间的权限,但是这个函数里的名字,并不会影响传过来之前的变量名
- }
- //test.c
- void DListTest1()
- {
- DLNode* plist = NULL;//哨兵位
- DLInit(&plist);//对头节点改变需要二级指针
-
- //测试尾插
- DLPushBack(plist, 1);
- DLPushBack(plist, 2);
- DLPushBack(plist, 3);
-
- //DLPushFront(plist, 11);
- //DLPushFront(plist, 22);
- //DLPushFront(plist, 33);
- DLPrint(plist);
- //链表销毁
- DLDesTroy(plist);//销毁完后是需要置为NULL的
- plist = NULL;
- }
- void des(DLNode** del)
- {
- free(*del);//拿到了plist的地址,对plist的指向改变
- *del = NULL;
- }
- void DListTest1()
- {
- DLNode* plist = NULL;//哨兵位
- DLInit(&plist);//对头节点改变需要二级指针
- //测试尾插
- DLPushBack(plist, 1);
- DLPushBack(plist, 2);
- DLPushBack(plist, 3);
- DLPrint(plist);
- //链表销毁
- DLDesTroy(plist);
- des(&plist);//这边我们创建一个单独销毁的函数
- }
- int main()
- {
- DListTest1();
- return 0;
- }
- #include "DList.h"
- void DListTest1()
- {
- //DLNode* plist = NULL;//哨兵位
- //DLInit(&plist);//对头节点改变需要二级指针
-
- //第二种初始化方式
- DLNode* plist = DLInit();
-
- 测试尾插
- //DLPushBack(plist, 1);
- //DLPushBack(plist, 2);
- //DLPushBack(plist, 3);
- //测试头插
- DLPushFront(plist, 11);
- DLPrint(plist);
- DLPushFront(plist, 22);
- DLPrint(plist);
- DLPushFront(plist, 33);
- DLPrint(plist);
-
- //测试尾删
- //DLDelBack(plist);
- //DLPrint(plist);
- //DLDelBack(plist);
- //DLPrint(plist);
- //DLDelBack(plist);
- //DLPrint(plist);
- //DLDelBack(plist);
- //DLPrint(plist);
-
- //测试头删
- //DLDelFront(plist);
- //DLPrint(plist);
- //DLDelFront(plist);
- //DLPrint(plist);
- //DLDelFront(plist);
- //DLPrint(plist);
- DLNode* find = DLFind(plist, 11);// 33 22 11
- if (find == NULL)
- printf("没找到\n");
- else
- printf("找到了\n");
-
- //在pos节点后插入
- DLInsert(find, 99);// 33 22 11 99
- DLPrint(plist);
-
- //删除pos节点
- DLErase(find);
- find = NULL;
- DLPrint(plist);
- }
- int main()
- {
- DListTest1();
- return 0;
- }
- #include "DList.h"
- //新空间
- DLNode* DLBuyNode(DLDataType x)
- {
- DLNode* newnode = (DLNode*)malloc(sizeof(DLNode));
- if (newnode == NULL)
- {
- perror("malloc nwe");
- exit(-1);//推出整个程序
- }
- newnode->data = x;
- newnode->next = newnode->prev = newnode;//申请新节点,需要自循环
- return newnode;
- }
-
- //双链表的初始化
- //void DLInit(DLNode** pphead)//只传参不返回值,因为可以对实参直接改变
- //{
- // *pphead = DLBuyNode(-1);
- //}
-
- //第二种初始化方法为了保证接口的一致性,让传递的值都是一级指针
- DLNode* DLInit()
- {
- DLNode* node = DLBuyNode(-1);
- return node;
- }
-
- //打印链表
- void DLPrint(DLNode* phead)
- {
- DLNode* pcur = phead->next;//头节点指向下一个节点,也就是第一个有效节点
- while (pcur != phead)
- {
- printf("%d->", pcur->data);
- pcur = pcur->next;
- }
- printf("\n");
- }
-
- //尾插
- void DLPushBack(DLNode* phead, DLDataType x)
- {
- assert(phead);
- DLNode* newnode = DLBuyNode(x);
- //phead phead->prev newnode
- newnode->prev = phead->prev;//phead->prev 是头节点指向的上一个节点也就是尾节点
- newnode->next = phead;
-
-
- phead->prev->next = newnode;//尾节点指向下一个节点
- phead->prev = newnode;
- }
-
- //头插
- void DLPushFront(DLNode* phead, DLDataType x)
- {
- assert(phead);//头节点不能为NULL
- DLNode* newnode = DLBuyNode(x);
- newnode->next = phead->next;
- newnode->prev = phead;
-
- //方法1
- //phead->next->prev = newnode;//第一个有效节点指向newnode
- //phead->next = newnode;//指向下一个节点
-
- //方法2
- phead->next = newnode;
- newnode->next->prev = newnode;
- }
-
- //尾删
- void DLDelBack(DLNode* phead)
- {
- //当phead->next != phead就正常执行
- assert(phead && phead->next != phead);//链表都为NULL你删什么?,如果是只剩一个头结点当然也不行
- DLNode* del = phead->prev;
- del->prev->next = phead;//删除的前一个节点指向phead
- phead->prev = del->prev;//头结点的前一个节点指向del->prev
- free(del);
- del = NULL;
- }
-
- //头删
- void DLDelFront(DLNode* phead)
- {
- assert(phead && phead->next != phead);//如果保错就说明,要么为NULL,要么只有一个头结点
- DLNode* del = phead->next;//第一个有效节点
- phead->next = del->next;
- del->next->prev = phead;
- free(del);
- del = NULL;
- }
-
- //查找
- DLNode* DLFind(DLNode* phead, DLDataType x)
- {
- assert(phead);
- DLNode* pcur = phead->next;//可能存在多次查找,其次记得是第一个有效节点
- while (pcur != phead)
- {
- if (pcur->data == x)
- {
- return pcur;
- }
- pcur = pcur->next;
- }
- return NULL;
- }
-
- //在指定位置插入
- void DLInsert(DLNode* pos, DLDataType x)
- {
- assert(pos);//防止phead == NULL链表
- DLNode* newnode = DLBuyNode(x);
- //pos newnode pos->next
- newnode->next = pos->next;
- newnode->prev = pos;
-
- pos->next->prev = newnode;
- pos->next = newnode;
- }
-
- //在指定位置删除
- void DLErase(DLNode* pos)
- {
- assert(pos);//可能会缺少phead的检查
- //pos->prev pos pos->next
- pos->next->prev = pos->prev;
- pos->prev->next = pos->next;
- free(pos);//pos置为NULL并不影响find
- pos = NULL;
- }
- #pragma once
- #define _CRT_SECURE_NO_WARNINGS
- #include <stdio.h>
- #include <stdlib.h>
- #include <assert.h>
- typedef int DLDataType;
- typedef struct ListNode
- {
- DLDataType data;
- struct ListNode* prev;//指向前一个节点
- struct ListNode* next;//指向下一个节点
- }DLNode;//链表节点
-
- //双链表初始化
- //void DLInit(DLNode** pphead);
-
- //第二种初始化方式
- DLNode* DLInit();
-
- //尾插
- void DLPushBack(DLNode* phead, DLDataType x);
-
- //头插
- void DLPushFront(DLNode* phead, DLDataType x);
-
- //尾删
- void DLDelBack(DLNode* phead);
-
- //头删
- void DLDelFront(DLNode* phead);
-
- //查找
- DLNode* DLFind(DLNode* phead, DLDataType x);
-
- //在指定位置插入
- void DLInsert(DLNode* pos, DLDataType x);
-
- //指定位置删除
- void DLErase(DLNode* pos);
这里只算是基础部分,当然最主要的是学会如何使用手里的工具
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。