• 4-29 c语言之【栈,队列,双向链表】


      今天学习了数据结构中栈,队列的知识

      相对于单链表来说,栈和队列就是添加的方式不同,队列就相当于排队,先排队的先出来(FIFO),而栈就相当于弹夹,先压进去的子弹后出来(FILO)。

    首先看一下栈(Stack)的实现

     1 #include<stdio.h>
     2 #include<stdlib.h>
     3 #define TRUE 1
     4 #define FALES 0
     5 typedef struct NODE
     6 {
     7     int i;
     8     struct NODE *pNext;                                        //指向的是  上一个从栈顶刚压入的结点
     9 }Stack;
    10 typedef int BOOL;                                            //因为c语言里没有布尔类型,所以用int模拟一下
    11 void Push(Stack **pTop,int i);
    12 BOOL IfEmpty(Stack *pTop);        
    13 Stack *Pop(Stack **pTop);                                    //出栈操作
    14 int main()
    15 {
    16     Stack *pTop = NULL;
    17 
    18 
    19 }
    20 void Push(Stack **pTop,int i)                            //压栈操作
    21 {
    22     Stack *pTemp = (Stack *)malloc(sizeof(Stack));
    23     pTemp->i = i;
    24     pTemp->pNext = NULL;
    25     
    26     pTemp->pNext = *pTop;
    27     *pTop = pTemp;
    28 
    29     return;
    30 }
    31 BOOL IfEmpty(Stack *pTop)                                            //因为c++的STL容器里存在判断栈是否为空的操作,在这模拟一下
    32 {
    33     if(pTop == NULL)
    34         return TRUE;
    35     return FALES;
    36 }
    37 Stack *Pop(Stack **pTop)
    38 {
    39     Stack *pPop = NULL;
    40     if(IfEmpty(*pTop))
    41     {
    42         return NULL;
    43     }
    44     else
    45     {
    46         pPop = *pTop;
    47         *pTop = (*pTop)->pNext;
    48         return pPop;
    49     }
    50 }

    其次队列(Queue)的实现非常简单,队列压入的实现就和单链表尾添加一样,而弹出就和单链表头删除是一样的,只不过不需要free直接返回队首指针即可;

     1 #include<stdio.h>
     2 #include<stdlib.h>
     3 #define TRUE 1
     4 #define FALSE 0
     5 typedef struct NODE
     6 {
     7     int i;
     8     struct NODE *pNext;
     9 }Queue;
    10 typedef int BOOL;
    11 int GetId();
    12 void QueueIn(Queue **ppHead,Queue **ppEnd);
    13 BOOL IfEmpty(Queue *pHead);
    14 Queue *QueueOut(Queue **ppHead,Queue **ppEnd);
    15 int main()
    16 {
    17     Queue *pHead = NULL;
    18     Queue *pEnd = NULL;
    19     Queue *p = NULL;
    20 
    21     QueueIn(&pHead,&pEnd);
    22     QueueIn(&pHead,&pEnd);
    23     QueueIn(&pHead,&pEnd);
    24     p = QueueOut(&pHead,&pEnd);
    25 
    26     return 0;
    27 
    28 }
    29 int GetId()
    30 {
    31     static int i = 0;
    32     i++;
    33     return i;
    34 }
    35 void QueueIn(Queue **ppHead,Queue **ppEnd)
    36 {
    37     Queue *pTemp = (Queue *)malloc(sizeof(Queue));
    38     pTemp->i = GetId();
    39     pTemp->pNext = NULL;
    40 
    41     if(*ppHead == NULL)
    42     {
    43         *ppHead = pTemp;
    44     }
    45     else
    46     {
    47         (*ppEnd)->pNext = pTemp;
    48     }
    49     *ppEnd = pTemp;
    50 }
    51 BOOL IfEmpty(Queue *pHead)
    52 {
    53     if(pHead == NULL)
    54         return TRUE;
    55     return FALSE;
    56 }
    57 Queue *QueueOut(Queue **ppHead,Queue **ppEnd)
    58 {
    59     Queue *pOut = NULL;
    60     if(IfEmpty(*ppHead) == TRUE)
    61         return NULL;
    62     else
    63     {
    64         pOut = *ppHead;
    65         *ppHead = (*ppHead)->pNext;
    66         return pOut;
    67     }
    68 }

    那么栈和栈区又有什么区别呢?先看这样一段程序

    1 #include<stdio.h>
    2 int main()
    3 {
    4   int i = 1;
    5   printf("%d   %d
     ",i,i++);
    6 
    7   return 0;
    8 }

    可能一打眼看 就认为是1  1,但测试后发现是 2  1,这就不免让人联想到先进后出的特点了,由于printf是一个标准输出库函数,i 和 i++都算做是两个实参,在函数中,形参也是一个局部变量,在函数这个堆区中存在,按照图中出栈的顺序先B后A,那么先 i++ 出来为 1 ,i 其次出来就为2了(启示就是,在栈区中 若一个函数的参数用了同一个变量 ,记得栈的特点)

    双向链表,故名思意就是有一个链表可正向可反向,也就是在添加每个结点的时候,加入一个指针,指向上一个结点的地址,代码如下:

     1 #include<stdio.h>
     2 #include<stdlib.h>
     3 typedef struct NODE
     4 {
     5     int id;
     6     struct NODE *pNext;
     7     struct NODE *pLast;                     //指向上个结点
     8 }List;
     9 void AddNode(List **ppHead,List **ppEnd,int id);
    10 int main()
    11 {
    12     List *pHead = NULL;
    13     List *pEnd = NULL;
    14     AddNode(&pHead,&pEnd,1);
    15     AddNode(&pHead,&pEnd,2);
    16     AddNode(&pHead,&pEnd,3);
    17     AddNode(&pHead,&pEnd,4);
    18 
    19     while(pHead)
    20     {
    21         printf("%d
    ",pHead->id);
    22         pHead = pHead->pNext;
    23     }
    24     printf("
    ");
    25 
    26 
    27     while(pEnd)
    28     {
    29         printf("%d
    ",pEnd->id);
    30         pEnd = pEnd->pLast;
    31     }
    32 
    33 
    34 }
    35 void AddNode(List **ppHead,List **ppEnd,int id)
    36 {
    37     List *pTemp = (List *)malloc(sizeof(List));
    38     pTemp->id = id;
    39     pTemp->pLast = NULL;
    40     pTemp->pNext = NULL;
    41 
    42     if(*ppHead == NULL)
    43     {
    44         *ppHead = pTemp;
    45         *ppEnd = pTemp;
    46     }
    47     else
    48     {
    49         (*ppEnd)->pNext = pTemp;
    50         pTemp->pLast = *ppEnd;
    51         *ppEnd = pTemp;
    52     }
    53     return;
    54 }

    最后看到了有两个小问题

    第一个 如何用两个栈实现一个队列  这个很简单,先全部压入第一个栈里,然后弹出再压出第二个栈里,最后弹出的就是队列的顺序,反反得正

      1 #include<stdio.h>
      2 #include<stdlib.h>
      3 typedef struct NODE
      4 {
      5     int id;
      6     struct NODE *pNext;
      7 }
      8 Stack;
      9 void Push1(Stack **pTop1);
     10 Stack *Pop1(Stack **pTop1);
     11 void Push2(Stack **pTop2,Stack *pNode);
     12 Stack *Pop2(Stack **pTop2);
     13 Stack *QueueOut(Stack **pTop1,Stack **pTop2);
     14 void InitStack(Stack **pTop1,int n);
     15 int IfEmpty(Stack *pTop1);
     16 int GetId();
     17 int main()
     18 {
     19     Stack *pTop1 = NULL;
     20     Stack *pTop2;
     21     Stack *pTemp = NULL;
     22     InitStack(&pTop1,5);
     23     pTemp = QueueOut(&pTop1,&pTop2);
     24     while(pTop2)
     25     {
     26         pTemp = QueueOut(&pTop1,&pTop2);
     27     }
     28 
     29     
     30 
     31     return 0;
     32 }
     33 int GetId()
     34 {
     35     static int i = 0;
     36     i++;
     37     return i;
     38 }
     39 void InitStack(Stack **pTop1,int n)
     40 {
     41     int i;
     42     for(i = 0;i < n;i++)
     43     {
     44         Push1(pTop1);
     45     }
     46     return;
     47 }
     48 void Push1(Stack **pTop1)
     49 {
     50     Stack *pTemp = (Stack *)malloc(sizeof(Stack));
     51     pTemp->id = GetId();
     52     pTemp->pNext = NULL;
     53 
     54     pTemp->pNext = *pTop1;
     55     *pTop1 = pTemp;
     56 
     57     return;
     58 }
     59 Stack *Pop1(Stack **pTop1)
     60 {
     61     Stack *pPop = NULL;
     62     if(*pTop1 == NULL)
     63     {
     64         return NULL;
     65     }
     66     else
     67     {
     68         pPop = *pTop1;
     69         *pTop1 = (*pTop1)->pNext;
     70         return pPop;
     71     }
     72 }
     73 void Push2(Stack **pTop2,Stack *pNode)
     74 {
     75     pNode->pNext = *pTop2;
     76     *pTop2 = pNode;
     77 
     78     return;
     79 
     80 }
     81 Stack *Pop2(Stack **pTop2)
     82 {
     83     Stack *pPop = NULL;
     84     if(*pTop2 == NULL)
     85     {
     86         return NULL;
     87     }
     88     else
     89     {
     90         pPop = *pTop2;
     91         *pTop2 = (*pTop2)->pNext;
     92         return pPop;
     93     }
     94 }
     95 int IfEmpty(Stack *pTop1)
     96 {
     97     if(pTop1 == NULL)
     98         return 1;
     99     return 0;
    100 }
    101 Stack *QueueOut(Stack **pTop1,Stack **pTop2)
    102 {
    103     while(IfEmpty(*pTop1) != 1)
    104         Push2(pTop2,Pop1(pTop1));
    105     
    106     return Pop2(pTop2);
    107 }

    第二个,如何快速的找到链表里倒数第n个结点,设置两个指针指向头,一个先往后走k个结点,然后一起走,当先走的那个到达尾结点时,后走的也就是倒数第k个结点了

     1 #include<stdio.h>
     2 #include<stdlib.h>
     3 typedef struct NODE
     4 {
     5     int id;
     6     struct NODE *pNext;
     7 }List;
     8 int GetId();
     9 void AddNode(List **ppHead,List **ppEnd);
    10 List *Search(List *pHead,List *pEnd,int n);
    11 int main()
    12 {
    13     List *pHead = NULL;
    14     List *pEnd = NULL;
    15     List *pTemp = NULL;
    16     int i;
    17     for(i = 0;i < 5;i++)
    18         AddNode(&pHead,&pEnd);
    19     pTemp = Search(pHead,pEnd,2);
    20     printf("%d
    ",pTemp->id);
    21 
    22 }
    23 int GetId()
    24 {
    25     static int i = 0;
    26     i++;
    27     return i;
    28 }
    29 void AddNode(List **ppHead,List **ppEnd)
    30 {
    31     List *pTemp = (List *)malloc(sizeof(List));
    32     pTemp->id = GetId();
    33     pTemp->pNext = NULL;
    34 
    35     if(*ppHead == NULL)
    36     {
    37         *ppHead = pTemp;
    38     }
    39     else
    40     {
    41         (*ppEnd)->pNext = pTemp;
    42 
    43     }
    44     *ppEnd = pTemp;
    45 }
    46 List *Search(List *pHead,List *pEnd,int n)
    47 {
    48     int i;
    49     List *pFast = pHead;
    50     List *pSlow = pHead;
    51     for(i = 0;i < n;i++)
    52     {
    53         pFast = pFast->pNext;
    54     }
    55     while(pFast)
    56     {
    57         pSlow = pSlow->pNext;
    58         pFast = pFast->pNext;
    59     }
    60     return pSlow;
    61 
    62 }

    2019-04-29 22:32:52 编程菜鸟自我反省,大佬勿喷,谢谢!!!

  • 相关阅读:
    线程高并发
    29(套接字)就是网络编程
    28线程
    27 枚举
    26静态导入和可变参数
    25JDK新特性
    25断言 assert关键字
    24单元测试 junit
    炫酷CSS
    PHP 汉字转拼音类
  • 原文地址:https://www.cnblogs.com/xgmzhna/p/10793351.html
Copyright © 2020-2023  润新知