欢迎来到Cefler的博客😁
🕌博客主页:那个传说中的man的主页
🏠个人专栏:题目解析
🌎推荐文章:题目大解析2
👉🏻线性表
概念:
线性表(linear list)是n个具有相同特性的数据元素的有限序列。 线性表是一种在实际中广泛使
用的数据结构,常见的线性表:顺序表、链表、栈、队列、字符串…
线性表在逻辑上是线性结构,也就说是连续的一条直线。但是在物理结构上并不一定是连续的,
线性表在物理上存储时,通常以数组
和链式结构
的形式存储。
顺序表
概念
顺序表是用一段
物理地址连续
的存储单元依次存储数据元素的线性结构,一般情况下采用数组存
储。在数组上完成数据的增删查改。
顺序表一般分为:
- 静态顺序表:使用定长数组存储元素
- 动态顺序表:使用动态开辟的数组存储(空间不够则增容)
用顺序表实现增删查改
SeqList.c
#include "SeqList.h"
SL s;
void Test1()
{
PushEndSL(&s, 1);
PushEndSL(&s, 2);
PushEndSL(&s, 3);
PushEndSL(&s, 4);
PushEndSL(&s, 5);
PushEndSL(&s, 6);
/*PushFrontSL(&s, 8);
PushFrontSL(&s, 9);
PushFrontSL(&s, 10);
PushFrontSL(&s, 11);*/
/*DelEndSL(&s);
DelFrontSL(&s);*/
//InsertSL(&s, 2, 2);
/*EraseSL(&s, 4);*/
/*ModifySL(&s, 2);*/
PrintSL(&s);
}
//int main()
//{
// InitSL(&s);
// Test1();
// DestroySL(&s);
// return 0;
//}
SeqList.c
#include "SeqList.h"
void CheckCapacitySL(SL* psl)
{
if (psl->sz == psl->capacity)//如果容量已满
{
SeqListType* tmp = (SeqListType*)realloc(psl->a, sizeof(SeqListType) * 2*(psl->capacity));//每次先扩容2倍大小
if (tmp == NULL)
{
perror("realloc fail");
return;
}
psl->a = tmp;
psl->capacity *= 2;
}
}
void InitSL(SL* psl)
{
psl->a = (SeqListType*)malloc(sizeof(SeqListType) * 4);//一开始初始化先开辟4大小空间
if (psl->a == NULL)
{
perror("malloc fail");
return;
}
psl->sz = 0;
psl->capacity = 4;
}
void DestroySL(SL* psl)
{
free(psl->a);
psl->a = NULL;
psl->sz = 0;
psl->capacity = 0;
}
void PushEndSL(SL* psl, SeqListType x)
{
CheckCapacitySL(psl);//检查容量
psl->a[psl->sz] = x;
psl->sz++;
}
void PushFrontSL(SL* psl, SeqListType x)
{
CheckCapacitySL(psl);//检查容量
for (int i = psl->sz - 1; i >= 0; i--)
{
psl->a[i + 1] = psl->a[i];
}
psl->a[0] = x;
psl->sz++;
}
void DelEndSL(SL* psl)
{
//assert(psl->sz>0);//为假报错
if (psl->sz == 0)//如果sz为0,则不能够再减了
return;
psl->sz--;
}
void DelFrontSL(SL* psl)
{
if (psl->sz == 0)//如果sz为0,则不能够再减了
return;
int i = 1;
for (i = 1; i < psl->sz; i++)
{
psl->a[i - 1] = psl->a[i];
}
psl->sz--;
}
void InsertSL(SL* psl, int pos, SeqListType x)
{
CheckCapacitySL(psl);//检查容量
assert(pos >= 0 && pos <= psl->sz);//判断pos的位置合不合理
int i = 0,num= psl->sz;
for (i = 0; i < psl->sz - pos; i++)
{
psl->a[num] = psl->a[num - 1];
num--;
}
psl->a[pos] = x;
psl->sz++;
}
void EraseSL(SL* psl, int pos)
{
assert(psl->sz > 0);//如果为0,再减sz就不礼貌喽
assert(pos>=1&&pos<=psl->sz);
int i = 0, num = pos;
for (i = 0; i < psl->sz - pos; i++)
{
psl->a[num-1] = psl->a[num];
num++;
}
psl->sz--;
}
int FindSL(SL* psl, SeqListType x)
{
for (int i = 0; i <psl->sz; i++)
{
if (psl->a[i] == x)
return i;//返回下标
}
return -1;
}
void ModifySL(SL* psl, int pos, SeqListType x)
{
assert(pos > 0 && pos <= psl->sz);
psl->a[pos - 1] = x;
}
void PrintSL(SL* psl)
{
int i = 0;
for (i = 0; i < psl->sz; i++)
{
printf("%d\n", psl->a[i]);
}
}
SeqList.h
#pragma once
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
//静态顺序库
typedef int SeqListType;//为了后期方便改存储的数据类型
#define N 10
//静态顺序库
//struct SeqList
//{
// SeqListType arr[N];
// int sz;
//};
//动态顺序库
typedef struct SeqList
{
SeqListType* a;
int sz;//存储的有效数据的个数
int capacity;//当前库的容量
}SL;
void InitSL(SL* psl);
void DestroySL(SL* psl);
void PushEndSL(SL* psl, SeqListType x);//尾部插入数据
void PushFrontSL(SL* psl, SeqListType x);//头部插入数据
void DelEndSL(SL* psl);//尾部删除数据
void DelFrontSL(SL* psl);//头部删除数据
void InsertSL(SL* psl, int pos, SeqListType x);//在内部插入数据
void EraseSL(SL* psl, int pos);//在内部删除数据
int FindSL(SL* psl, SeqListType x);//查找一个数字
void ModifySL(SL* psl, int pos, SeqListType x);//修改某数字
void PrintSL(SL* psl);//打印数据
👉🏻 链表
概念:
链表是一种物理存储结构上非连续、非顺序的存储结构,数据元素的逻辑顺序是通过链表
中的指针链接次序实现的 。
简单链表实现
Slist Test.c
#include "Slist.h"
void Test_1()
{
SL* p = NULL;
PushFrontSL(&p, 1);
PushFrontSL(&p, 2);
PushFrontSL(&p, 3);
PushFrontSL(&p, 4);
PrintSL(p);
}
int main()
{
Test_1();
return 0;
}
Slist.c
#define _CRT_SECURE_NO_WARNINGS 1
#include "Slist.h"
void PushFrontSL(SL** phead, SlistType x)//为何要二级指针?若我们改的是一级指针本身(即地址)
//地址本身就是一个数据,即一个数值,当我们对地址进行“动手脚”时,在传参形式上,就不能叫做传址,而是传值了
//所以如果要修改地址,则要使用二级指针才行
{
SL* newnode = (SL*)malloc(sizeof(SL*));//开辟新空间
if (newnode == NULL)
{
perror("malloc fail");
return;
}
newnode->data = x;
newnode->next = *phead;
*phead = newnode;
}
void PrintSL(SL* phead)
{
SL* cur = phead;
while (cur != NULL)
{
printf("%d->", cur->data);
cur = cur->next;
}
printf("NULL\n");
return;
}
为何要二级指针?若我们改的是一级指针本身(即地址)
地址本身就是一个数据,即一个数值,当我们对地址进行“动手脚”时,在传参形式上,就不能叫做传址,而是传值了
Slist.h
#pragma once
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
typedef int SlistType;
typedef struct Slist
{
SlistType data;
struct Slist* next;
}SL;
void PushFrontSL(SL** phead, SlistType x);
void PrintSL(SL* phead);
🖌链表进行尾插
代码示例:
SL* CreatNewnode(SlistType x)//创建一个开辟新空间的函数(适用于尾插开辟新空间)
{
SL* newnode = (SL*)malloc(sizeof(SL*));//开辟新空间
if (newnode == NULL)
{
perror("malloc fail");
return;
}
newnode->data = x;
newnode->next = NULL;
return newnode;
}
void PushEndSL(SL* phead, SlistType x)
{
SL* tail = phead;
if (tail != NULL)
{
tail = tail->next;
}
SL* newnode = CreatNewnode(x);
tail = newnode;
}
先说结论:上述的代码是错误的。接下来,通过图解看下该代码的具体流程
这么一看,好像没什么问题啊。
但这里有个很致命的问题是,在PushEndSL函数中的变量tail和newnode都是局部变量
这就会导致上述代码中
SL* newnode = CreatNewnode(x);
tail = newnode;
这一部分,在函数结束后,newnode和tail作为局部变量会销毁,而原本newnode指向的那个malloc开辟的空间成为“孤空间”(指向该空间的指针消失了),而该空间是不会销毁的,因为是动态开辟,其在内存中的堆区,而该孤空间得不到释放,会造成内存泄漏。
而至于tail,就更不用说了,也是该销毁的销毁,从而无法真正做到将链表给连接起来
所以我们该如何改良呢?
void PushEndSL(SL* phead, SlistType x)
{
SL* tail = phead;
if (tail->next != NULL)
{
tail = tail->next;
}
SL* newnode = CreatNewnode(x);
tail->next = newnode;
}
我们只是简单的将newnode处的地址赋给tail->next处,因为该处位于开辟的动态空间中,不会随着函数的结束而销毁,这才把节点地址存储起来了,而这里也将判断语句改为tail->next != NULL,当next指向的为空指针时,停止访问,进行开辟新空间。
但实际上这里代码还是存在BUG,就是当phead的值为NULL时,此时tail->next对空指针进行解引用会出现错误,所以,在这里我们需要考虑两种情况,空链表
和非空链表
优化如下👇🏻
void PushEndSL(SL* phead, SlistType x)
{
SL* newnode = CreatNewnode(x);
//1.空链表
if (phead == NULL)
{
phead = newnode;
}
//2.非空链表
else
{
SL* tail = phead;
if (tail->next != NULL)
{
tail = tail->next;
}
tail->next = newnode;
}
}
如果到这里,你觉得是不是已经差不多了,我只能说:少年,还太年轻了。
哪里又有问题呢?
通过仔细观察,我们会发现,这里我们对地址进行了传值操作,phead只是作为一份临时拷贝,对其赋值,根本影响不了实参,所以,要想实现最后的成功,我们要动用二级指针
了,进行传址操作
优化如下👇🏻
void PushEndSL(SL** phead, SlistType x)
{
SL* newnode = CreatNewnode(x);
//1.空链表
if (*phead == NULL)
{
*phead = newnode;
}
//2.非空链表
else
{
SL* tail = *phead;
if (tail->next != NULL)
{
tail = tail->next;
}
tail->next = newnode;
}
}
嗯,终于大功告成了,此时我们终于能实现尾插的功能了。
🖌链表进行尾删
我们进行尾删的思路为:
- 找尾:找到节点中next指向的空间为空指针
- 释放:释放该节点空间
- 置空:将指向该节点空间的指针置为NULL,也就是倒数第二个节点的next指针
需要考虑的三种情况
- 没有节点,即空链表情况
- 节点为1个
- 多个节点
尾删功能实现👇🏻
void EraseEndSL(SL** pphead)
{
SL* tail = *pphead;
//1.空链表情况,温柔的检查
//if (*pphead==NULL)
//{
// return;
//}
//暴力检查
assert(*pphead);
//2.一个节点
if (tail->next == NULL)
{
free(tail);
tail = NULL;
}
else
{
while ((tail)->next->next != NULL)
{
tail = tail->next;
}
free(tail->next);
tail->next = NULL;
}
}
🖌链表进行头删
头删的思路为
将第一个节点空间释放,让phead指向第二个节点空间
也需要考虑三种情况
- 没有节点,即空链表情况
- 节点为1个
- 多个节点
头删功能实现👇🏻
void EraseFrontSL(SL** pphead)
{
//1.空链表
assert(*pphead);
//2.一个节点
if ((*pphead)->next == NULL)
{
free(*pphead);//释放空间
*pphead = NULL;
}
else
{
SL* tail = *pphead;
/*SL* tail_next = tail->next;*/
*pphead = (*pphead)->next;
free(tail);
/*tail = tail_next;*/
}
}
🖌链表进行内部插入(前插)
void InsertFrontSL(SL** pphead, SL* pos, SlistType x)
{
assert(pphead);//因为phead不可能为NULL,所以需要断言一下(如果出现NULL则不合理)
assert(pos);
/*assert(*pphead);*///这个不能断言,因为可以允许*phead为空指针,因为空指针也能进行插入数据
if ((*pphead)->next == NULL)
{
PushFrontSL(pphead, x);//如果节点只有一个,就进行头插
}
else
{
SL* cur = *pphead;
while (1)
{
if (cur->next == pos)
break;
cur = cur->next;
}
SL* newnode = CreatNewnode(x);
newnode->next = pos;
cur->next = newnode;
}
}
🖌链表进行内部插入(后插)
void InsertEndSL(SL** pphead, SL* pos, SlistType x)
{
assert(pphead);//因为phead不可能为NULL,所以需要断言一下(如果出现NULL则不合理)
assert(pos);
//if ((*pphead)->next == NULL)
//{
// PushEndSL(pphead, x);//如果节点只有一个,就进行尾插
//}
/*else
{*/
SL* cur = *pphead;
while (1)
{
if (cur == pos)
break;
cur = cur->next;
}
SL* newnode = CreatNewnode(x);
newnode->next = pos->next;
cur->next = newnode;
/*}*/
}
🖌链表进行内部删除(pos位置删除)
void EraseSL(SL** pphead, SL* pos)
{
assert(pphead && pos && *pphead);
SL* cur = *pphead;
if (cur == pos)
{
EraseFrontSL(pphead);//一个节点时进行头删
}
while (1)
{
if (cur->next == pos)
break;
cur = cur->next;
}
cur->next = pos->next;
free(pos);
}
🖌链表进行内部删除(pos位置后一个节点删除)
void EraseAfterSL(SL** pphead, SL* pos)
{
assert(pphead && pos && *pphead);
assert(pos->next);
SL* pos_next =pos->next ;
pos->next = pos_next->next;
free(pos_next);
}
🖌链表进行查找
SL* FindSL(SL* phead, SlistType x)
{
SL* cur = phead;
while (cur)//当cur指针指向的为NULL,则无数据,停止循环
{
if (cur->data == x)
return cur;
cur = cur->next;
}
return NULL;//找不到返回空指针
}
👉🏻 链表OJ题
移除链表元素
法一:
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* struct ListNode *next;
* };
*/
struct ListNode* removeElements(struct ListNode* head, int val){
struct ListNode* prev=NULL,*cur=head;
while(cur)
{
if(cur->val==val)
{
if(prev)
{
prev->next=cur->next;
free(cur);
cur=prev->next;
}
else//如果第一个就是,进行头删
{
cur=head->next;
free(head);
head=cur;
}
}
else
{
prev=cur;
cur=cur->next;
}
}
return head;
}
法二:尾插
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* struct ListNode *next;
* };
*/
struct ListNode* removeElements(struct ListNode* head, int val){
struct ListNode* newnode=NULL,*cur=head,*tail=NULL;
while(cur)
{
if(cur->val!=val)//如果不等于进行尾插(在newnode中)
{
if(tail==NULL)//如果一开始第一个就要进行尾插
{
newnode=tail=cur;
}
else
{
tail->next=cur;//进行插入
tail=tail->next;//目前已经存放进去数据的位置(最前位)
}
cur=cur->next;
tail->next=NULL;//防止最后一个值是val,而将最后一个值free后,tail->next不能再指向这个空间了,所以令其为NULL
}
else
{
struct ListNode* del=cur;//存储起来要删除的该节点
cur=cur->next;
free(del);
}
}
return newnode;
}
链表的中间节点
快慢指针作法
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* struct ListNode *next;
* };
*/
struct ListNode* middleNode(struct ListNode* head){
struct ListNode* slow=head,*fast=head;
if(head==NULL)
return NULL;
while(fast!=NULL&&fast->next!=NULL)
{
slow=slow->next;
fast=fast->next->next;
}
return slow;
}
链表中倒数第k个结点
牛客链接:链表中倒数第k个结点
法一:
struct ListNode* FindKthToTail(struct ListNode* pListHead, int k )
{
struct ListNode* tail=pListHead,*cur=pListHead;
if(pListHead==NULL)
return NULL;
int i=0;
for(i=0;i<k;i++)
{
if(cur==NULL)
break;
cur=cur->next;
}
if(i<k)//此时整个链表长度小于k
return NULL;
while(cur)
{
tail=tail->next;
cur=cur->next;
}
return tail;
}
反转链表
法一:三指针
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* struct ListNode *next;
* };
*/
struct ListNode* reverseList(struct ListNode* head)
{
struct ListNode* prev=NULL,*tail=head,*cur=head;
if(head==NULL)
return NULL;
if(cur->next==NULL)
return cur;
cur=cur->next;//cur先走一步
while(1)
{
tail->next = prev;
prev = tail;
if (cur->next != NULL)
{
tail = cur;
cur = cur->next;
}
else
break;
}
cur->next=tail;
return cur;
}
示例代码:
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* struct ListNode *next;
* };
*/
/*双指针+一个暂时的指针*/
struct ListNode* reverseList(struct ListNode* head){
if (head == NULL)
return head;
struct ListNode* pre = NULL;
struct ListNode* curr = head;
struct ListNode* tmp = curr->next;
while (curr != NULL){
curr->next = pre; /*现在的指针倒转*/
pre = curr;
curr = tmp;
if(tmp)
tmp = tmp->next;
}
return pre;
}
法二:头插逆转
struct ListNode* reverseList(struct ListNode* head){
struct ListNode* cur=head,*newnode=NULL;
while(cur)
{
struct ListNode* next=cur->next;
cur->next=newnode;
newnode=cur;
cur= next;
}
return newnode;
}
合并两个有序链表
法一:比较小的先尾插
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* struct ListNode *next;
* };
*/
struct ListNode* mergeTwoLists(struct ListNode* list1, struct ListNode* list2){
struct ListNode* newhead=NULL,*tail=NULL;
if(list1==NULL)//存在一个链表为空,直接返回另一个链表
return list2;
if(list2==NULL)
return list1;
while(list1&&list2)
{
if(list1->val<=list2->val)
{
if(newhead==NULL)//第一次插入
{
newhead=tail=list1;
}
else
{
tail->next=list1;
tail=tail->next;
}
list1=list1->next;//当成功插入完一个节点后,节点往后走一步
}
else
{
if(newhead==NULL)//第一次插入
{
newhead=tail=list2;
}
else
{
tail->next=list2;
tail=tail->next;
}
list2=list2->next;
}
}
if(list1==NULL)
{
while(list2)
{
tail->next=list2;
tail=tail->next;
list2=list2->next;
}
}
if(list2==NULL)
{
while(list1)
{
tail->next=list1;
tail=tail->next;
list1=list1->next;
}
}
return newhead;
}
链表分割
#include <cstddef>
class Partition {
public:
ListNode* partition(ListNode* pHead, int x)
{
struct ListNode* lesshead,*lesstail,*greathead,*greattail;
struct ListNode* cur=pHead;
lesshead=lesstail=(struct ListNode*)malloc(sizeof(struct ListNode));
greathead=greattail=(struct ListNode*)malloc(sizeof(struct ListNode));
while(cur)
{
if(cur->val<x)
{
lesstail->next=cur;
lesstail=lesstail->next;
}
else
{
greattail->next=cur;
greattail=greattail->next;
}
cur=cur->next;
}
lesstail->next=greathead->next;
greattail->next=nullptr;
pHead=lesshead->next;
free(lesshead);
free(greathead);
return pHead;
}
};
链表中的哨兵
在head中我们一般不存放数据
head的功能在于我们引用head不需要担心head会是NULL,上题中我们就是运用哨兵的这一优点解决问题的。
链表的回文结构
struct ListNode* middleNode(struct ListNode* head){
struct ListNode* slow=head,*fast=head;
if(head==NULL)
return NULL;
while(fast!=NULL&&fast->next!=NULL)
{
slow=slow->next;
fast=fast->next->next;
}
return slow;
}
struct ListNode* reverseList(struct ListNode* head){
if (head == NULL)
return head;
struct ListNode* pre = NULL;
struct ListNode* curr = head;
struct ListNode* tmp = curr->next;
while (curr != NULL){
curr->next = pre; /*现在的指针倒转*/
pre = curr;
curr = tmp;
if(tmp)
tmp = tmp->next;
}
return pre;
}
class PalindromeList {
public:
bool chkPalindrome(ListNode* head) {
struct ListNode* mid=middleNode(head);//先找中点
struct ListNode* rear=reverseList(mid);//再逆转后部
while(rear)
{
if(head->val!=rear->val)
return false;
head=head->next;
rear=rear->next;
}
return true;
}
};
相交链表
法一:遍历法(时间复杂度O(N^2))
struct ListNode *getIntersectionNode(struct ListNode *headA, struct ListNode *headB) {
struct ListNode * cura=headA,*curb=headB;
while(cura)
{
curb=headB;
while(curb)
{
if(cura==curb)
return cura;
curb=curb->next;
}
cura=cura->next;
}
return NULL;
}
示例代码:时间复杂度O(m+n)
struct ListNode *getIntersectionNode(struct ListNode *headA, struct ListNode *headB) {
// struct ListNode*curA=headA;
// struct ListNode*curB=headB;
struct ListNode*nA=headA;
struct ListNode*nB=headB;
int lenA=0,lenB=0;
//这里不应该将判断条件设为nA和nB,因为虽然判断到最后一个节点,
//但是下一步nA和nB都指向哪了不知道
while(nA->next)
{
++lenA;
nA=nA->next;
}
while(nB->next)
{
++lenB;
nB=nB->next;
}
if(nA!=nB)
{
return NULL;
}
int len=abs(lenA-lenB);
struct ListNode*longList=headA;
struct ListNode*shortList=headB;
if(lenB>lenA)
{
longList=headB;
shortList=headA;
}
while(len--)
{
longList=longList->next;
}
while(longList!=shortList)
{
longList=longList->next;
shortList=shortList->next;
}
return longList;
}
判断是否为环形链表
bool hasCycle(struct ListNode *head) {
struct ListNode* slow=head,*fast=head;
if(head==NULL)
return false;
while(fast&&fast->next)
{
fast=fast->next->next;
slow=slow->next;
if(fast==slow)
return true;
}
return false;
}
环形链表 II
环形链表 II
思路:
struct ListNode *detectCycle(struct ListNode *head) {
struct ListNode* slow=head,*fast=head;
if(head==NULL)
return NULL;
while(fast&&fast->next)
{
fast=fast->next->next;
slow=slow->next;
if(fast==slow)
{
struct ListNode* meet=fast;
while(head!=meet)
{
head=head->next;
meet=meet->next;
}
return meet;
}
}
return NULL;
}
👉🏻双向链表
SeqList.c
#define _CRT_SECURE_NO_WARNINGS 1
#include "SeqList.h"
ListNode* CreatNewnode(Listtype x)
{
ListNode* newnode = (ListNode*)malloc(sizeof(ListNode));
newnode->prev = NULL;
newnode->next = NULL;
newnode->data = x;
return newnode;
}
ListNode* InitList()
{
ListNode* phead= (ListNode*)malloc(sizeof(ListNode));
phead->prev = phead;
phead->next = phead;
return phead;
}
void ListPushFront(ListNode* phead, Listtype x)
{
assert(phead);
ListNode* head = phead->next;
ListNode* newnode = CreatNewnode(x);
phead->next = newnode;
newnode->prev = phead;
newnode->next = head;
head->prev = newnode;
}
void LTPopBack(ListNode* phead)
{
assert(phead);
ListNode* tail = phead->prev;
ListNode* tailprev = tail->prev;
tailprev->next = phead;
phead->prev = tailprev;
free(tail);
tail = NULL;
}
void ListPushBack(ListNode* phead, Listtype x)
{
ListNode* tail=phead->prev;
ListNode* newnode = CreatNewnode(x);
/*tail->next = newnode;
newnode->prev = tail;
newnode->next = phead;
phead->prev = newnode;*/
tail->next = newnode;
newnode->prev = tail;
phead->prev = newnode;
newnode->next = phead;
}
void LTPopFront(ListNode* phead)
{
ListNode* head = phead->next;
ListNode* headnext = head->next;
phead->next = headnext;
headnext->prev = phead;
free(head);
}
ListNode* LTFind(ListNode* phead,Listtype x)
{
assert(phead);
ListNode* cur = phead->next;
while (cur != phead)
{
if (cur->data == x)
return cur;
cur = cur->next;
}
return NULL;
}
void LTPosPush(ListNode* phead, ListNode* pos, Listtype x)
{
assert(phead);
ListNode* posprev = pos->prev;
ListNode* newnode = CreatNewnode(x);
posprev->next = newnode;
newnode->prev = posprev;
newnode->next = pos;
pos->prev = newnode;
}
void LTPosErase(ListNode* phead, ListNode* pos)
{
assert(phead);
ListNode* posprev = pos->prev;
ListNode* posnext = pos->next;
posprev->next = posnext;
posnext->prev = posprev;
free(pos);
pos = NULL;
}
void LTPrint(ListNode* phead)
{
assert(phead);
ListNode* cur = phead->next;
printf("Guard<-->");
while (cur != phead)
{
printf("%d<-->", cur->data);
cur = cur->next;
}
printf("Guard");
}
SeqList.h
#pragma once
#include <stdio.h>
#include <assert.h>
typedef int Listtype;
typedef struct ListNode
{
struct ListNode* prev;
struct ListNode* next;
Listtype data;
}ListNode;
ListNode* InitList();
void ListPushFront(ListNode* phead, Listtype x);//头插
void ListPushBack(ListNode* phead, Listtype x);//尾插
void LTPopFront(ListNode* phead);//头删
void LTPopBack(ListNode* phead);//尾删
ListNode* LTFind(ListNode* phead,Listtype x);//查找某一元素
void LTPosPush(ListNode* phead, ListNode* pos, Listtype x);//在某一位置进行插入
void LTPosErase(ListNode* phead, ListNode* pos);//在某一位置进行删除
ListNode* CreatNewnode(Listtype x);
void LTPrint(ListNode* phead);//打印
如上便是本期的所有内容了,如果喜欢并觉得有帮助的话 ,希望可以博个点赞+收藏+关注🌹🌹🌹❤️ 🧡 💛,学海无涯苦作舟,愿与君一起共勉成长