必不可少需要掌握的嵌入式知识(2) -- 经典数据结构总结之 (链表,队列)

数据结构

    定义:    

    数据结构是计算机组织,存储数据的方式。数据结构是指相互之间存在一种或多种特定关系的元素集合,大部分的数据结构的实现都需要借助C语言中的指针和结构体类型。

    几种常见的数据结构

    1,线性数据结构:元素之间一般存在一对一关系,是最常用的一种数据结构,比如:数组,栈,队列和线性表。

    2,树形数据结构:结点间具有层次关系,每一层的结点能且只能和上一层的一个结点相关,但同时可以和下一层的多个结点相关,称为一对多关系,比如:树,堆

    3,图形结构:允许多个结点之间相关,被称为多对多关系,分为有向图和多向图。  

    下面对这几种数据结构做简单介绍:

    数组:存放着一组相同类型的数据,需要预先指定数组的长度,有一维,二维,多维数组。

    链表:是C语言中一种应用广泛的数据结构,它采用动态分配内存的方式实现,用一组任意的存储单元存放数据元素,一般为每个数据元素增加指针域,用来指向后继元素。

    数组和链表的区别

    从逻辑结构来看:数组必须事先定义固定的长度,不能适应数据动态的增减的情况;链表进行动态的内存分配,可以适应数据动态的增减情况,且可以方便的插入删除数据项(数组中插入删除数据项时,需要移动其他数据项)

    从内存存储来看:(静态)数组从栈中分配内存(用NEW分配在堆中),对于程序员方便快捷,但自由度小;链表在堆中分配内存,自由度大但申请管理比较麻烦

    从访问方式来看:数组在内存中是连续存储的,因此可以利用下标索引进行随机访问;链表是链式存储结构,在访问数据的时候只能通过线性的方式由前到后顺序访问,所以访问效率比数组低。

    栈、队列、线性表:可采取顺序存储和链式存储的方法进行存储。

    顺序存储:借助数据元素在存储空间中的相对位置来表示元素之间的逻辑关系

    链式存储:借助表示数据元素存储地址的指针表示元素之间的逻辑关系

    :只允许在序列末端进行操作,栈的操作只能在栈顶进行,一般栈又被称为后进先出或先进后出的线性结构。

        顺序栈:采用顺序存储结构的栈称为顺序栈,即需要用一片地址连续的空间来存储栈的元素,顺序栈的类型定义如下:

        typedef struct{

            ElemType *elem;        //存储空间的基址

            int top;                        //栈顶元素的下一个元素,简称栈顶位标

            int size;                       //当前分配的存储容量

            int increment;              //扩容时增加的存储容量

        }SqStack;

        链栈:采用链式存储结构的栈称为链栈:

        typedef struct LsNode{

            ElemType data;            //数据域

            struct LSNode *next;    //指针域

        }LSNode, *LsStack;          //结点和链栈类型

        链栈使用C语言的实现如下所示

        /*
       The realization of the stack.
       */
        #include <stdio.h>
        #include <stdlib.h>
        #include <malloc.h>

        //Define the node struct.
        typedef struct Node
        {
            int data;           //Data.
            struct Node *pNext; //Pointer the next node.
        }NODE, *PNODE;          //NODE is equivalent to Node,PNODE is equivalent to struct Node *.

        //定义栈的结构体
        typedef struct Stack
        {
            PNODE pTop;         //栈顶结点
            PNODE pBottom;      //栈底结点
        }STACK, *PSTACK;

        //Function declarations
        void initStack (PSTACK pStack);             //初始化栈函数
        void pushStack (PSTACK pStack, int val);    //入栈函数
        int popStack (PSTACK pStack, int *pVal);    //出栈函数
        void traverseStack (PSTACK pStack);         //遍历栈的函数
        int isEmpty (PSTACK pStack);                //判断栈是否为空的函数
        void clearStack (PSTACK pStack);            //清空栈的函数

        int main (void)
        {
            STACK stack;                //定义一个栈变量
            int val;                    //用来保存出栈的内容
            initStack (&stack);         //调用初始化栈函数
            pushStack (&stack, 10); //调用入栈函数
            pushStack (&stack, 20); //调用入栈函数
            pushStack (&stack, 30); //调用入栈函数
            pushStack (&stack, 40); //调用入栈函数
            pushStack (&stack, 50); //调用入栈函数
            traverseStack (&stack); //调用遍历栈的函数
            //调用出栈的函数
            if (popStack (&stack, &val))
                printf ("出栈失败!\n");
            else
                printf ("出栈成功,出栈元素值为:%d.\n", val);
            //调用清空栈的函数
            clearStack (&stack);
            traverseStack (&stack);

            return 0;
        }

        void initStack (PSTACK pStack)
        {
            pStack->pTop = (PNODE)malloc(sizeof(NODE));             //创建一个空结点,让 pTOP 指向它

             if (NULL != pStack->pTop)
            {
                pStack->pBottom = pStack->pTop;                     //将 pBottom 也指向空结点
                pStack->pTop->pNext = NULL;                         //清空空结点的指针欲
            }
            else                                                    //如果分配内存失败
            {
                printf ("内存分配失败,程序退出!\n");
                exit (-1);
            }

            return ;
        }

        void pushStack (PSTACK pStack, int val)
        {
            PNODE pNew = (PNODE)malloc (sizeof (NODE));             //动态创建一个新结点

            pNew->data = val;                                       //设置新结点的数据域的值
            pNew->pNext = pStack->pTop;                             //将新结点的指针域指向之前的栈顶结点
            pStack->pTop = pNew;                                    //pTop 指向新的结点

            return ;
        }

        int popStack (PSTACK pStack, int *pVal)
        {
            if (isEmpty (pStack))
                return -1;
            else
            {
                //先保存栈顶元素的地址,然后将 pTop 指向下一元素,最后释放之前栈顶元素的内存
                PNODE tmpNode = pStack->pTop;
                *pVal = pStack->pTop->data;
                pStack->pTop = pStack->pTop->pNext;
                free (tmpNode);
                tmpNode = NULL;
            }

            return 0;
        }

        void traverseStack (PSTACK pStack)
        {
            PNODE tmpNode = pStack->pTop;                           //将栈顶赋给一个临时结点,因为在遍历栈的时候不能销毁栈

            //循环遍历栈,直到栈底
            while (tmpNode != pStack->pBottom)
            {
                printf ("%d ", tmpNode->data);
                tmpNode = tmpNode->pNext;
            }

             printf ("\n");

            return ;
        }

        int isEmpty (PSTACK pStack)
        {
            if (pStack->pTop == pStack->pBottom)
                return -1;
            else
                return 0;
        }

        void clearStack (PSTACK pStack)
        {
            //栈为空则推出该函数
            if (isEmpty (pStack))
                   return ;
            else
            {
                PNODE p1 = pStack->pTop;
                PNODE p2 = NULL;
                //循环释放内存
                while (p1 != pStack->pBottom)
                {
                    p2 = p1->pNext;
                    free (p1);
                    p1 = p2;

                 }
                //将栈顶和栈底指向同一个指针域为空的结点
                pStack->pTop = pStack->pBottom;
            }

            return ;
        }

 

    队列:只允许在序列两端进行操作,一般队列也被称为先进先出的线性结构

    循环队列:采用顺序存储结构的队列,需要按队列可能的最大长度分配存储空间,其类型定义如下:

    typedef struct 

    {

        Elemtype *base;                        //存储空间的基址

        int front;                                    //队头位标

        int rear;                                    //队尾位标,指示队尾元素的下一位置

        int maxSize;                            //maxSize

    }SqQueue;

    链队列:采用链式存储结构的队列称为链队列,一般需要设置头尾指针:

    typedef struct LQNode

    {

        Elemtype data;                                    //数据域

        struct LQNode *next;                           //指针域

    }LQNode, *QueuePtr;                              //结点和链栈类型

    typedef struct

    {

        QueuePtr front;                                    //队头指针

        QueuePtr rear;                                    //队尾指针

    }LQueue;                                                //栈队列类型

 

    以下为链队列的实现:

    /*
   The realization of the queue.
   */
    #include <stdio.h>
    #include <stdlib.h>

    typedef int ElementType;

    typedef struct QNode
    {
        ElementType Element;                                //数据域
        struct QNode *pNext;                    //指向下一个元素的指针域
    }QNode, *QNodePtr;

    typedef struct Node
    {
        QNodePtr front;                         //队列头
        QNodePtr rear;                          //队列尾
    }Node, *NodePtr;

    ElementType isEmpty (NodePtr pNode);                            /*判断一个队列是否为空*/
    NodePtr CreateQueue (void);                                     /*创建一个队列*/
    void DisposeQueue (NodePtr pNode);                              /*销毁队列*/
    void MakeEmpty (NodePtr pNode);                                 /*清空队列*/
    void Enqueue (ElementType x, NodePtr pNode);                    /*入队*/
    ElementType Front (NodePtr pNode);                              /*若队列不为空,返回头元素数据域*/
    void Dequeue (NodePtr pNode);                                   /*若队列不为空,则删除头元素*/
    ElementType FrontAndDequeue (NodePtr pNode);                    /*返回队列中每个元素的数据域*/

    ElementType isEmpty (NodePtr pNode)
    {
        return pNode->front == pNode->rear;
    }

    NodePtr CreateQueue (void)
    {
        NodePtr pNode;

        pNode = (NodePtr)malloc (sizeof (Node));
        pNode->front = pNode->rear = (QNodePtr)malloc (sizeof (QNode));

        if (!pNode->front)
        {
            printf ("out of space! CreateQueue failed!\n");
            return NULL;
        }
        pNode->front->pNext = NULL;
        return pNode;
    }

    void MakeEmpty (NodePtr pNode)
    {
        if (NULL == pNode)
        {
            printf ("Must user CreateQueue first\n");

            return ;
        }
        else
            while (!isEmpty (pNode))
                Dequeue (pNode);
    }

    void DisposeQueue (NodePtr pNode)
    {
        while (pNode->front)
        {
            pNode->rear = pNode->front->pNext;
            free (pNode->front);
            pNode->front = pNode->rear;
        }
        printf ("\nDispose queue completed!!!");
    }

    void Enqueue (ElementType x, NodePtr pNode)
    {
        QNodePtr p = (QNodePtr)malloc (sizeof (QNode));

        if (!p)
        {
            printf ("Out of space!\n");
            return ;
        }

         p->Element = x;
        p->pNext = NULL;
        pNode->rear->pNext = p;
        pNode->rear=p;
    }

    ElementType Front (NodePtr pNode)
    {
        if (!isEmpty (pNode))
            return pNode->front->pNext->Element;
        return 0;   /*Return value used to avoid warning*/
    }

    void Dequeue (NodePtr pNode)
    {
        if (!isEmpty (pNode))
        {
            QNodePtr p = (QNodePtr)malloc (sizeof (QNode));
            if (!pNode)
            {
                printf ("Out of place!--Dequeue\n");
                return ;
            }
            p = pNode->front->pNext;
            pNode->front->pNext = p->pNext;
            if (pNode->rear == p)
                pNode->rear = pNode->front;

            free (p);
        }
    }

    /*
       获取队列元素中的数据元素
     */
    ElementType FrontAndDequeue (NodePtr pNode)
    {
        if (!isEmpty (pNode))
        {
            QNodePtr p = (QNodePtr)malloc (sizeof (QNode));
            if (!p)
            {
                printf ("Out of space!--FrontAndDequeue\n");
                return ;
            }
            p = pNode->front->pNext;
            ElementType temp;
            temp = p->Element;
            pNode->front->pNext = p->pNext;
            if (pNode->rear == p)
                pNode->rear = pNode->front;
            free (p);
            return temp;
        }

        printf ("Empty queue!\n");

         return 0;           /*Return value used to avoid warning*/
    }


    int main (void)
    {
        int n, num, m;
        int i;

        NodePtr pNode = CreateQueue ();
        printf ("initialization complete.\n");
        if (isEmpty(pNode))
            printf ("queue is empty!\n");
        printf ("Please input the number of elements in the queue:\n");
        scanf ("%d", &n);
        printf ("Please input %d elements put in queue:", n);
        for (i = 0; i < n; i++)
        {
            scanf ("%d", &num);
            Enqueue (num, pNode);
        }
        printf ("Front element:%d.\n", Front(pNode));
        printf ("Element is queue:");
        while (!isEmpty (pNode))
            printf ("%3d", FrontAndDequeue (pNode));

        DisposeQueue (pNode);

         printf ("\n");

        return 0;
    }

    

    

 

    

转载于:https://my.oschina.net/xolsenberg/blog/756573

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值