zoukankan      html  css  js  c++  java
  • 单链表

    其实单链表就像是一个绿皮火车,火车头为单链表的头结点,火车尾为单链表的最后一个节点(节点的指针域指为NULL的节点),而中间的节点,即为车厢,每个车厢(节点)都有其座位(节点的数据域)和连接下一车厢的安全绳(节点的指针域)。

    咱们如果想造火车呢,得先设计一下火车每个车厢的结构和火车头。

    在造火车前,咱们先看看造火车需要什么原材料吧!然后咱们才能买原材料造火车啊!

    #include "stdio.h"    
    #include "string.h"
    #include "ctype.h"      
    #include "stdlib.h"   
    #include "io.h"  
    #include "math.h"  
    #include "time.h"
    
    #define OK 1
    #define ERROR 0
    #define TRUE 1
    #define FALSE 0
    
    #define MAXSIZE 20 /* 存储空间初始分配量 */
    
    typedef int Status;/* Status是函数的类型,其值是函数结果状态代码,如OK等 */
    typedef int ElemType;/* ElemType类型根据实际情况而定,这里假设为int */

    原材料买完了,咱们得先设计一下火车的车厢结构,有的人说怎么不先设计火车头呢?从本人角度来说,火车头和火车厢的构造差不多,车厢咱们造好了,利用车厢在来做火车头被!

    typedef struct Node
    {
        ElemType data;
        struct Node *next;
    }Node;

    此时,咱们的车厢做好了,但是忘记了一件事,火车总得有名字吧,比如什么和谐号啊啥的,因此咱们也给车厢起个名字吧!就叫做LinkList吧!

    typedef struct Node *LinkList; 

    这回咱么该建火车头了!

    Status InitList(LinkList *L)
    {
        *L = (LinkList)malloc(sizeof(Node)); /* 产生头结点,并使L指向此头结点 */
        if (!(*L)) /* 存储分配失败 */
            return ERROR;
        (*L)->next = NULL; /* 指针域为空 */
    
        return OK;
    }

    有的人说,车头有了,但是火车头没有连接车厢啊!好吧!接下来咱们来开始连接车厢了,

    但有人提出先把第一节的车厢连在火车头,然后让第二节车厢连在第一节车厢末尾,以此类推,这是个好方法,

    但又有人说,先把第一节的车厢连在火车头,然后让第二节车厢连在火车头后面,第一节车厢前面,第三车厢连在火车头后面,第二节车厢前面,虽然这么做处于理性逻辑来说,比较费时,但是也是一种方法吧。

    咱们先实现第一种方法吧,即第一节的车厢连在火车头,然后让第二节车厢连在第一节车厢末尾,以此类推。我们叫这种方法为尾插法。

    /*  随机产生n个元素的值,建立带表头结点的单链线性表L(尾插法) */
    void CreateListTail(LinkList *L, int n)
    {
        LinkList p, r;
        int i;
        srand(time(0));                      /* 初始化随机数种子 */
        *L = (LinkList)malloc(sizeof(Node)); /* L为整个线性表 */
        r = *L;                                /* r为指向尾部的结点 */
        for (i = 0; i<n; i++)
        {
            p = (Node *)malloc(sizeof(Node)); /*  生成新结点 */
            p->data = rand() % 100 + 1;           /*  随机生成100以内的数字 */
            r->next = p;                        /* 将表尾终端结点的指针指向新结点 */
            r = p;                            /* 将当前的新结点定义为表尾终端结点 */
        }
        r->next = NULL;                       /* 表示当前链表结束 */
    }

    现在咱们开始实现第二种方法吧!即头插法

    /*  随机产生n个元素的值,建立带表头结点的单链线性表L(头插法) */
    void CreateListHead(LinkList *L, int n)
    {
        LinkList p;
        int i;
        srand(time(0));                         /* 初始化随机数种子 */
        *L = (LinkList)malloc(sizeof(Node));
        (*L)->next = NULL;                      /*  先建立一个带头结点的单链表 */
        for (i = 0; i<n; i++)
        {
            p = (LinkList)malloc(sizeof(Node)); /*  生成新结点 */
            p->data = rand() % 100 + 1;             /*  随机生成100以内的数字 */
            p->next = (*L)->next;
            (*L)->next = p;                        /*  插入到表头 */
        }
    }

    火车刚造完,老板发话了,有领导来乘坐我们的火车,但这位领导比较特殊,有钱,有自己的车厢,咱们为了领导的安全,选择咱们火车的第i节车厢后面加这个车厢,车厢后面在连接剩余的车厢。卧槽!什么破领导,有钱就了不起啊!哎,没办法,只是心里想想而已,最后也得干啊!

    /* 初始条件:顺序线性表L已存在,1≤i≤ListLength(L), */
    /* 操作结果:在L中第i个位置之前插入新的数据元素e,L的长度加1 */
    Status ListInsert(LinkList *L, int i, ElemType e)
    {
        int j;
        LinkList p, s;
        p = *L;
        j = 1;
        while (p && j < i)     /* 寻找第i个结点 */
        {
            p = p->next;
            ++j;
        }
        if (!p || j > i)
            return ERROR;   /* 第i个元素不存在 */
        s = (LinkList)malloc(sizeof(Node));  /*  生成新结点(C语言标准函数) */
        s->data = e;
        s->next = p->next;      /* 将p的后继结点赋值给s的后继  */
        p->next = s;          /* 将s赋值给p的后继 */
        return OK;
    }

    领导终于走了,但是老板说,第i节的车厢坏了,需要进行修理,等列车有空,就把它拆下来吧!,妈的,fuck,费事真多!

    /* 初始条件:顺序线性表L已存在,1≤i≤ListLength(L) */
    /* 操作结果:删除L的第i个数据元素,并用e返回其值,L的长度减1 */
    Status ListDelete(LinkList *L, int i, ElemType *e)
    {
        int j;
        LinkList p, q;
        p = *L;
        j = 1;
        while (p->next && j < i)    /* 遍历寻找第i个元素 */
        {
            p = p->next;
            ++j;
        }
        if (!(p->next) || j > i)
            return ERROR;           /* 第i个元素不存在 */
        q = p->next;
        p->next = q->next;            /* 将q的后继赋值给p的后继 */
        *e = q->data;               /* 将q结点中的数据给e */
        free(q);                    /* 让系统回收此结点,释放内存 */
        return OK;
    }

    总算完活了,但领导又说,你查查咱们现在有多少车厢吧!没办法!活总得干!

    /* 初始条件:顺序线性表L已存在。操作结果:返回L中数据元素个数 */
    int ListLength(LinkList L)
    {
        int i = 0;
        LinkList p = L->next; /* p指向第一个结点 */
        while (p)
        {
            i++;
            p = p->next;
        }
        return i;
    }

    刚查完车厢,领导又说,查查第i个车厢是谁在管理!

    /* 初始条件:顺序线性表L已存在,1≤i≤ListLength(L) */
    /* 操作结果:用e返回L中第i个数据元素的值 */
    Status GetElem(LinkList L, int i, ElemType *e)
    {
        int j;
        LinkList p;        /* 声明一结点p */
        p = L->next;        /* 让p指向链表L的第一个结点 */
        j = 1;        /*  j为计数器 */
        while (p && j<i)  /* p不为空或者计数器j还没有等于i时,循环继续 */
        {
            p = p->next;  /* 让p指向下一个结点 */
            ++j;
        }
        if (!p || j>i)
            return ERROR;  /*  第i个元素不存在 */
        *e = p->data;   /*  取第i个元素的数据 */
        return OK;
    }

    总算做完了,领导又说,小e在哪个车厢啊!好吧!接着干活吧!

    /* 初始条件:顺序线性表L已存在 */
    /* 操作结果:返回L中第1个与e满足关系的数据元素的位序。 */
    /* 若这样的数据元素不存在,则返回值为0 */
    int LocateElem(LinkList L, ElemType e)
    {
        int i = 0;
        LinkList p = L->next;
        while (p)
        {
            i++;
            if (p->data == e) /* 找到这样的数据元素 */
                return i;
            p = p->next;
        }
    
        return 0;
    }

    几天之后~因领导管理不善,火车车厢因意外被烧毁,就剩个车头了。哈哈!真开心,总算丫的以后没事了

    /* 初始条件:顺序线性表L已存在。操作结果:将L重置为空表 */
    Status ClearList(LinkList *L)
    {
        LinkList p, q;
        p = (*L)->next;           /*  p指向第一个结点 */
        while (p)                /*  没到表尾 */
        {
            q = p->next;
            free(p);
            p = q;
        }
        (*L)->next = NULL;        /* 头结点指针域为空 */
        return OK;
    }

    总结:

    1、关于功能函数形参应该为ListNode* L和ListNode L的问题

    若需要对整个链表进行初始化、插入、删除、清空则需要将功能函数里的形参设置为ListNode* L,因为这是对整个链表数据位置进行操作。

    若不需要改动整个链表各个数据的位置,仅是对整个链表的查询,则将功能形参设置为ListNode L

  • 相关阅读:
    环境是如何建立的 启动文件有什么
    环境中存储的是什么
    串行 并行 异步 同步
    TPC-H is a Decision Support Benchmark
    进程通信类型 管道是Linux支持的最初Unix IPC形式之一 命名管道 匿名管道
    删除环境变量
    14.3.2.2 autocommit, Commit, and Rollback 自动提交 提交和回滚
    14.3.2.2 autocommit, Commit, and Rollback 自动提交 提交和回滚
    14.3.2.1 Transaction Isolation Levels 事务隔离级别
    14.3.2.1 Transaction Isolation Levels 事务隔离级别
  • 原文地址:https://www.cnblogs.com/zhuifeng-mayi/p/10800297.html
Copyright © 2011-2022 走看看