moc 发表于 2018-8-25 10:38:23

022+-链表基础及基本操作

本帖最后由 moc 于 2018-9-23 16:10 编辑

1、链表基本概念
链表:是一种物理存储单元上非连续的存储结构,由一系列结点(链表中每一个元素称为结点)组成,结点动态生成,结点与结点之间通过指针链接。
                每个结点包括两个部分:一部分是存储数据元素的数据域,另一部分是存储下一个结点地址的指针域。
链表的特点:
        1 链表是一种常用的数据结构,它通过指针将一些列数据结点,连接成一个数据链。相对于数组,链表具有更好的动态性。
        2 数据域用来存储数据,指针域用于建立与下一个结点的联系。
        3 建立链表时无需预先知道数据总量的,可以随机的分配空间,可以高效的在链表中的任意位置实时插入或删除数据。
        4 链表的开销,主要是访问顺序性和组织链的空间损失。
约定:
        •头结点、当前结点、前趋结点、后继结点新建结点
        •pHead、pCurrent、 pPrior、    pNext、   pMalloc
链表编程关键点:
        1、指针指向谁,就把谁的地址赋给指针
        2、辅助指针变量&操作逻辑的关系
2、静态链表
        手工依次为各结点建立指向关系,不能动态增加或减少结点,应用范围小。
struct AdvTeacher
{
        char name;
        int age;
        struct AdvTeacher *next;
};
        struct AdvTeacher t1, t2, t3;
        struct AdvTeacher *p;

        t1.age = 10;
        t2.age = 20;
        t3.age = 30;

        t1.next = &t2;//建立结点之间的指向
        t2.next = &t3;
        t3.next = NULL;
        //遍历链表
        while (p)
        {
                printf("age:%d\n", p->age);
                p = p->next;
        }
3、带头结点的单项链表

        头结点作为链表的开始,第一个结点为业务结点的开始,在进行接口的封装和设计时,链表的对外属性只有指向头结点的指针,其余的操作通过封装好的函数进行。
1.创建链表
        创建链表的头结点,需要在函数内申请内存空间,返回内存空间的首地址(指针函数,二级指针做输出)。
2.循环打印链表
        通过辅助指针记录当前位置,在链表中循环。
3. 指定结点前插入结点,如果没找到指定结点插到最后
        建立要插入的结点,建立两个辅助指针变量,一个指向当前结点,一个指向当前结点的前一个结点,循环每个结点,如果找到指定结点break,最后新结点链到当前结点,前一个结点链到新结点。
4.删除指定的结点
        循环每个结点,找到指定结点后删除并返回。
5.链表的逆置操作

        1.当链表只有头结点或只有一个业务结点不需要逆置,直接返回即可。
        2.准备环境:p保存第一个结点,q保存第二个结点
        3.从第二个结点开始操作,先缓存q的下一个结点,然后逆置(让第二个结点指向第一个结点),然后p,q各向后移一个对第三个结点做同样操作,知道q的指向NULL.
        4.最后把原先的第一个结点指向NULL,头结点指向p即可。
示例代码:
#include "stdlib.h"
#include "stdio.h"
#include "string.h"
#define _CRT_SECURE_NO_WARNINGS

typedef struct Node
{
        int data;
        struct Node *pNext;
}SLIST;

SLIST *Creat_SList()
{
        int data = 0;

        // 1建立头结点并初始化
        SLIST *pHead = NULL, *pm = NULL, *pCur = NULL;
        pHead = (SLIST*)malloc(sizeof(SLIST));
        if (pHead == NULL)
        {
                return -1;
        }
        pHead->data = 0;
        pHead->pNext = NULL;
        pCur = pHead;

        // 2循环建立结点,结点中的数据域由键盘输入
        printf("\n Please enter the data of node(-1:quit):");
        scanf("%d", &data);

        while (data != -1)
        {
                // 不断的malloc新结点, 并为数据域赋值
                pm = (SLIST*)malloc(sizeof(SLIST));
                if (pm == NULL)
                {
                        SList_Destory(pHead);
                        return NULL;
                }
                pm->data = data;
                pm->pNext = NULL;

                // 新结点加入链表
                pCur->pNext = pm;
                pCur = pm;

                printf("\n Please enter the data of node(-1:quit):");
                scanf("%d", &data);
        }

        return pHead;2.
}
//打印链表中的每一个值
int SList_Print(SLIST *pHead)
{
        SLIST *pCur = NULL;
        if (pHead == NULL)
        {
                return -1;
        }
        // 准配环境
        pCur = pHead->pNext;
        printf("\nBegin   ");
        while (pCur)
        {
                printf("%d ", pCur->data);
                pCur = pCur->pNext;
        }
        printf("End\n ");

}

// 在结点数值为x的前面插入y,如果没找到加到最后
int SList_NodeInsert(SLIST *pHead, int x, int y)
{
        SLIST *pCur = pHead, *pPre = NULL, *pTemp = NULL;
        if (pHead == NULL)
        {
                return -1;
        }
        pTemp = (SLIST*)malloc(sizeof(SLIST));
        if (pTemp == NULL)
        {
                return -2;
        }
        pTemp->data = y;
        while (pCur)   // 查找值为x结点的前一个结点
        {
                if (pCur->data == x)
                {
                        break;
                }
                pPre = pCur;
                pCur = pCur->pNext;
        }
        // 新结点链接到后继结点
        pTemp->pNext = pPre->pNext;
        // 让前驱结点链接到pTemp
        pPre->pNext = pTemp;

        return 0;
}

// 删除值为y的结点,如果不存在则打印删除结点不存在
int SList_NodeDel(SLIST *pHead, int y)
{
        SLIST *pCur = pHead, *pPre = NULL;
        if (pHead == NULL)
        {
                return -1;
        }
        while (pCur)
        {
                if (pCur->data == y)
                {
                        pPre->pNext = pCur->pNext;
                        free(pCur);
                        return 0;
                }
                pPre = pCur;
                pCur = pCur->pNext;
        }
        printf("值为%d结点不存在!\n", y);

}

// 链表逆置操作   //从第二个结点开始逆置
int SList_revse(SLIST *pHead)
{
        SLIST *p = NULL, *q = NULL, *t = NULL;
        if (pHead == NULL)
        {
                return -1;
        }
        if (pHead->pNext == NULL || pHead->pNext->pNext == NULL)
        {
                return 0;
        }
        // 准备环境
        p = pHead->pNext;
        q = pHead->pNext->pNext;
        while (q != NULL)
        {
                //1. 逆置之前做个缓存
                t = q->pNext;
                //2.开始逆置
                q->pNext = p;
                //3.p,q分别后移
                p = q;
                q = t;
        }

        // 扫尾工作
        pHead->pNext->pNext = NULL;
        pHead->pNext = p;
        return 0;

}

// 销毁整个链表
int SList_Destory(SLIST *pHead)
{
        SLIST *pCur = pHead, *pTemp = NULL;
        if (pHead == NULL)
        {
                return -1;
        }
        while (pCur)
        {
                // 缓存后继结点
                pTemp = pCur->pNext;
                // 删除当前结点
                free(pCur);
                // 当前结点下移
                pCur = pTemp;

        }
        return 0;
}

void main()
{
        SLIST *pHead = NULL;
        pHead = Creat_SList();
        SList_Print(pHead);
        SList_NodeInsert(pHead, 20, 19);
        SList_Print(pHead);
        SList_NodeDel(pHead, 20);
        SList_Print(pHead);
        SList_revse(pHead);
        SList_Print(pHead);
        SList_Destory(pHead);
        system("pause");
}

页: [1]
查看完整版本: 022+-链表基础及基本操作