双向链表

来源:互联网 发布:直通车关键词优化 展现 编辑:程序博客网 时间:2024/06/01 09:13

由于通过地址能访问指定的内存存储单元,因此可以说,地址“指向”该内存存储单元(如同说,房间号“指向”某一房间一样)。故将地址形象化地称为“指针”,意思是通过它能找到以它为地址的内存单元。一个变量的地址称为该变量的“指针”。如果有一个变量专门用来存放另一个变量的地址(即指针),则它称为“指针变量”。在许多高级程序设计语言中有专门用来存放内存单元地址的变量类型,这就是指针类型。指针变量就是具有指针类型的变量,它是用于存放内存单元地址的。

通过变量名访问一个变量是直接的,而通过指针访问一个变量是间接的。就好像要在学生公寓中找一位学生,不知道他的姓名,也不知道他住哪一间房,但是知道101房间里有他的地址,走进101房间后看到一张字条:“ 找我请到302”,这时按照字条上的地址到302去,便顺利地找到了他。这个101房间,就相当于一个指针变量,字条上的字便是指针变量中存放的内容(另一个内存单元的地址),而住在302房间的学生便是指针所指向的内容。

指针作为维系结点的纽带,可以通过它实现链式存储。假设有五个学生某一门功课的成绩分别为A、B、C、D和E,这五个数据在内存中的存储单元地址分别为1248、1488、1366、1022和1520,其链表结构如下图所示。

单链表

链表有一个“头指针”变量,上图中以 head表示,它存放一个地址,该地址指向链表中第一个结点,第一个结点又指向第二个结点……直到最后一个结点。该结点不再指向其他结点,它称为“表尾”,它的地址部分存放一个“NULL”(表示“空地址”),链表到此结束。链表中每个结点都包括两个部分:用户需要用的实际数据和下一个结点的地址。

可以看到链表中各结点在内存中可以不是连续存放的。要找到某一结点C,必须先找到其上一个结点B,根据结点B提供的下一个结点地址才能找到C。链表有一个“头指针”,因此通过“头指针”可以按顺序往下找到链表中的任一结点,如果不提供“头指针”,则整个链表都无法访问。链表如同一条铁链一样,一环扣一环,中间是不能断开的。打个比方,幼儿园的老师带领孩子出来散步,老师(作为头指针)牵着第一个小孩的手,第一个小孩的另一只手牵着第二个孩子……这就是一个“链”,最后一个孩子有一只手空着,他是“链尾”。要找这个队伍,必须先找到老师,然后按顺序找到每一个孩子。

上图的链表每个结点中只有一个指向后继结点的指针,该链表称为单链表。其实结点中可以有不止一个用于链接其他结点的指针。如果每个结点中有两个用于链接其他结点的指针,一个指向前趋结点(称前趋指针),另一个指向后继结点(称后继指针),则构成双向链表。双向链表如下图所示。

双向链表

链表的一个重要特点是插入、删除操作灵活方便,不需移动结点,只需改变结点中指针域的值即可。而数组由于用存储单元的邻接性体现数组中元素的逻辑顺序关系,因此对数组进行插入和删除运算时,可能需要移动大量的元素,以保持这种物理和逻辑的一致性。如数组中有m个元素,往第i(i < m)个元素后面插入一个新元素,需要将第i+1个元素至第m个元素共m-i个元素向后移动。

代码详解:

#include <stdio.h>#include <stdlib.h>#include <time.h>#include <malloc.h>#include<assert.h>typedef struct Link{    int nValue;    struct Link *pPrev;    struct Link *pNext;}Link, *PLink;                      //双向链表对象包含三个内容,存储的数值,指向前一个对象的指针,指向下一个对象的指针PLink Create( ){    PLink pLink = (PLink)malloc(sizeof(Link));    pLink->nValue = 0;    pLink->pPrev = NULL;    pLink->pNext = NULL;    return pLink;                           }                                                  //创建一个表头,存在数据和指向下一个对象的指针//按从小到大的顺序插入数据PLink Insert(PLink pLink, int nValue){    if (NULL == pLink)    {        printf("链表未创建成功!\n");        return NULL;    }    PLink pTmp = (PLink)malloc(sizeof(Link)); //对插入的数据开辟一个存储空间,    pTmp->nValue = nValue;                   //初始化链表中的对象    pTmp->pNext = NULL;    pTmp->pPrev = NULL;    PLink pCur = pLink;                          //链表的首地址,就是指表头    while (pCur->pNext != NULL && nValue >= pCur->pNext->nValue)     //按照从小到大进行插入数据    {        pCur = pCur->pNext;    }    if (pCur->pNext == NULL)        {//插入到最后一个结点后面        pTmp->pPrev = pCur;        pCur->pNext = pTmp;    }    if (nValue < pCur->pNext->nValue)    {//插入到中间位置        pTmp->pNext = pCur->pNext;        pCur->pNext->pPrev = pTmp;        pTmp->pPrev = pCur;        pCur->pNext = pTmp;    }    return pLink;}void Delete(PLink pLink, int nValue){    if (NULL == pLink)    {        printf("链表未创建成功!\n");        return;    }    PLink pCur = pLink;     bool bDel = false;    while (pCur->pNext != NULL )     {        //将判断放在while里面是为了能删除所有等于nValue的结点        if (pCur->pNext->nValue == nValue)        {            PLink pTmp = pCur->pNext;            if (NULL == pTmp->pNext)              {//删除最后一个结点                pCur->pNext = NULL;            }            else            {                pCur->pNext = pTmp->pNext;                pTmp->pNext->pPrev = pCur;            }                    bDel = true;            free(pTmp);        }        else        {            pCur = pCur->pNext;        }    }    if (!bDel)    {        printf("链表中没有数据 %d,无法删除!\n", nValue);    }}PLink Find(PLink pLink, int nValue){    PLink pCur = pLink->pNext;    while (NULL != pCur->pNext)    {        if (pCur->nValue == nValue)        {            return pCur;        }        pCur = pCur->pNext;    }    return NULL;}void Print(PLink pLink){    if (pLink->pNext == NULL)    {        printf("链表为空!\n");        return;    }    PLink pCur = pLink->pNext;    while (pCur != NULL)    {        printf("%d ", pCur->nValue);        pCur = pCur->pNext;    }}bool IsEmpty(PLink pLink){    return pLink->pNext == NULL;}void Destroy(PLink pLink){    PLink pCur = pLink;    PLink pDel = NULL;    PLink pNext = NULL;    while (pCur->pNext != NULL)    {        pDel = pCur->pNext;        if (NULL == pDel->pNext)        {//销毁最后一个结点            pCur->pNext = NULL;        }        else        {            pDel->pNext->pPrev = pCur;            pCur->pNext = pDel->pNext;        }          free(pDel);        printf("\n");        Print(pLink);    }    free(pLink);}int main(){    PLink pLink = Create();    pLink = Insert(pLink, 1);    pLink = Insert(pLink, 5);    pLink = Insert(pLink, 8);    pLink = Insert(pLink, 4);    pLink = Insert(pLink, 4);    Delete(pLink, 8);//    if (NULL != Find(pLink, 4))//    {//        printf("链表中有该数据!\n");//    }//    else//    {//        printf("链表中没有该数据!\n");//    }    Print(pLink);       // Destroy(pLink);system("pause");    return 0;}





0 0
原创粉丝点击