当前位置:   article > 正文

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\n ",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\n",pHead->id);
22         pHead = pHead->pNext;
23     }
24     printf("\n");
25 
26 
27     while(pEnd)
28     {
29         printf("%d\n",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\n",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 编程菜鸟自我反省,大佬勿喷,谢谢!!!

转载于:https://www.cnblogs.com/xgmzhna/p/10793351.html

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/花生_TL007/article/detail/660704
推荐阅读
相关标签
  

闽ICP备14008679号