双向链表的删除和销毁、内核链表

双向链表

双向链表的删除

错误代码实例

int DelteDouList(LinkNode *pHead, DataType TmpData)
{
    LinkNode *pTmpNode = NULL;
    pTmpNode = pHead->pNext;
    if (pTmpNode == NULL)
    {
        return -1;
    }
while(pTmpNode!=NULL)
{
    if(pTmpNode->Data==TmpData)
    {
        pNextNode = pTmpNode->pNext;
        pTmpNode->pPre->pNext = pTmpNode->pNext;
        if(pTmpNode->pNext!=NULL)
        {
        pTmpNode->pNext->pPre = pTmpNode->pPre;
        }
        pTmpNode = pTmpNode->pNext;
        free(pTmpNode->pPre);
    }
    else if(pTmpNode->Data!=TmpData)
    {
        pTmpNode = pTmpNode->pNext;
    }   
 } 
return 0;
}

在错误代码中,先将pTmpNode的前后节点相连(此时并没有和两个节点断开连接,如果按照节点连接的指向,依旧可以找到前后两个节点,因此在代码中选择将pTmpNode向后移动),随后让pTmpNode节点向后移动,错误之处在于,经过处理的pTmpNode的后一个节点的前一个已经变成了pTmpNode的前一个节点,在释放空间时,释放的已经不是我们所指定的空间。

正确代码

​
int DelteDouList(LinkNode *pHead, DataType TmpData)
{
    LinkNode *pTmpNode = NULL;
    LinkNode *pNextNode =   NULL;
    pTmpNode = pHead->pNext;
    if (pTmpNode == NULL)
    {
        return -1;
    }
while(pTmpNode!=NULL)
{
    if(pTmpNode->Data==TmpData)
    {
        pNextNode = pTmpNode->pNext;
        pTmpNode->pPre->pNext = pTmpNode->pNext;
        if(pTmpNode->pNext!=NULL)
        {
        pTmpNode->pNext->pPre = pTmpNode->pPre;
        }
        free(pTmpNode);
        pTmpNode = pNextNode;
    }
    else if(pTmpNode->Data!=TmpData)
    {
        pTmpNode = pTmpNode->pNext;
    }   
 } 
return 0;
}

​

双向链表的销毁

int DestoryDouList(LinkNode **ppHead)
{
    LinkNode *pTmpNode = NULL;
    pTmpNode = (*ppHead)->pNext;
    while (pTmpNode!= NULL)
    {
        free(pTmpNode->pPre);
        pTmpNode = pTmpNode->pNext;
    }    
    free(pTmpNode);
    *ppHead = NULL;
    return 0;
}

内核链表

内核链表是数据包含节点,因此在使用过程中可以由用户决定存放数据的类型

typedef struct student
{
      struct list_head node;
        char name[32];
        char sex;
        int age;
        int score;
}data_t;


int main(void)
{
    struct  list_head head;
    struct list_head *pTmpNode = NULL;
    data_t *pData = NULL;

    //初始化空白节点
    INIT_LIST_HEAD(&head);

    data_t tmpdata1 = {{NULL,NULL},"张三",'f',18,100};
    list_add(&tmpdata1.node,&head);
    data_t tmpdata2 = {{NULL,NULL},"李四",'f',18,88};
    list_add(&tmpdata2.node,&head);
    data_t tmpdata3 = {{NULL,NULL},"王二",'f',18,70};
    list_add(&tmpdata3.node,&head);
    data_t tmpdata4 = {{NULL,NULL},"张张",'m',16,100};
    list_add(&tmpdata4.node,&head);
   
   list_for_each(pTmpNode,&head)
   {
    pData = (data_t *)pTmpNode;
    printf("%s ",pData->name);
    printf("%c ",pData->sex);
    printf("%d ",pData->age);
    printf("%d ",pData->score);
    printf("\n");
   }

   return 0;
}

是只允许在一端进行插入或删除的线性表。首先栈是一种线性表,但限定这种线性表只能在某一端进行插入和删除操作。(具有先进后出的特点)

 栈顶:允许入栈出栈的一端称为栈顶
 栈底:不允许入栈和出栈的一端称为栈底
 入栈(压栈):将数据元素放入栈顶
 出栈(弹栈):将数据元素从栈顶位置取出

分类

空增栈
空减栈
满增栈
满减栈

关于循序栈的函数(创建,遍历...)

#include "seqstack.h"

SeqStack *CreateSeqStack(int MaxLen)
{
    //1.申请标签空间
    SeqStack *pTmpSatck = NULL;
    pTmpSatck = malloc(sizeof(SeqStack));
    if (NULL == pTmpSatck)
    {
        return NULL;
    }

    //2.对每个成员赋初值
    pTmpSatck->tLen = MaxLen;
    pTmpSatck->Top =0;
    //3.申请存放数据的空间
    DataType *pTmpData = NULL;
    pTmpData = malloc(sizeof(DataType)*MaxLen);
    pTmpSatck->pData = pTmpData;
    //4.返回标签地址 
    return pTmpSatck;
}

int IsFullSeqStack(SeqStack *pTmpStack)
{  
    if(pTmpStack->tLen == pTmpStack->Top)
    {
        return 1;
    }
    else if(pTmpStack->tLen>pTmpStack->Top)
    {
        return 0;
    }
}

int IsEmptySeqStack(SeqStack *pTmpStack)
{
    if(pTmpStack->Top == 0)
    {
        return 1;
    }
    else
    return 0;
}

int EnterSeqStack(SeqStack *pTmpStack, DataType TmpData)
{
    if (IsFullSeqStack(pTmpStack))
    {
        return -1;
    }

    pTmpStack->pData[(pTmpStack->Top) ] = TmpData;
    (pTmpStack->Top)++;
    return 0;
}

DataType PopSeqStack(SeqStack *pTmpStack)
{
    if (IsEmptySeqStack(pTmpStack))
    {
        return -1;
    }

    (pTmpStack->Top)--;

    return pTmpStack->pData[pTmpStack->Top];
}


int DestroySeqStack(SeqStack **ppTmpStack)
{
    int i = 0;
    free((*ppTmpStack)->pData);
    free(*ppTmpStack);
    *ppTmpStack = NULL;
}

内核链表与栈

//内核链表形(把存放数据的类型交给用户决定)
typedef struct data
{
    struct list_head node;
    int data;
}data_t;

int main(void)
{
    struct list_head *ptmpnode = NULL;
    data_t d[5] = {
                    {{NULL,NULL},1},
                    {{NULL,NULL},2},
                    {{NULL,NULL},3},
                    {{NULL,NULL},4},
                    {{NULL,NULL},5}
    };
    int i = 0;
    //定义链表空节点,并初始化
    struct list_head head;
    INIT_LIST_HEAD(&head);
    //将五个数据头插法插入链表中
    for(i = 0;i < 5;i++)
    {
         list_add(&d[i].node, &head);
    }
      //只要链表不为空将第一个节点出栈
    while (!list_empty(&head))
    {   
        ptmpnode = head.next;
        printf("%d ", list_entry(ptmpnode, data_t, node)->data);
        list_del(head.next);
    }
    printf("\n");

    return 0;
}

list_entry()函数

#define list_entry(ptr, type, member)					\
	((type *)((char *)(ptr)-(unsigned long)(&((type *)0)->member)))

在该函数中能够直接得到结构体成员的值,并将其转化为自己想要的类型。

(unsigned long)&((type *)0)->member)):在该部分中主要为了获得结构体成员在结构体中的偏移量。

(char *)(ptr):是指该结构体的首地址的位置

两者的差值即为成员变量的首地址。

队列

队列也是一种线性表,其特殊性在于队列的基本操作是线性表的子集。队列按“先进先出”的规则进行操作,故称其为操作受限的线性表。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值