• 数据结构-队列(数组实现)


    我们使用数组来实现:定义了四个函数

    EnQueue(x)、DeQueue(x)、front()、IsEmpty()

    这四个函数时间复杂度是O(1)orConstant time,我们是用循环数组来实现的

    循环数组的概念

    我们原来的数组是这样子的:

     我们使用循环数组以后变成如下这样:

     

    循环数组的原理

    编程实战

    四个函数与队列相关的函数

    我们将数组、队头和队尾还有数组长度定义为全局变量

    队列的定义是:先进先出,插入必须是在队尾进行的,删除必须是在队头进行的,队列被用来模拟一系列需要等待的场景

     

    EnQueue(x)入队、DeQueue(x)出队、front()返回对首的值、IsEmpty()看队列是否为空

    1. int front = -1;//队尾
    2. int rear = -1;//对头
    3. int A[10];//我们定义一个数组来实现队列
    4. int N=10;//数组的长度为N,N=10
    5. int Front(void) {
    6. //检查队列是否为空,只有front不为-1的时候才返回A[front]
    7. return A[front];
    8. }
    9. bool IsEmpty(void) {
    10. if ((front == -1) && (rear == -1))//表示队列为空,front==rear 要么为空,要么为一个元素;
    11. return 1;
    12. else
    13. return 0;
    14. }
    15. void EnQueue(int x) {//调用完EnQueue之后的队列,front和rear是一样的
    16. if ((rear+1)%N==front)//如果rear已经等于数组A的最大索引值,我们就不能插入元素了//rear == sizeof(A) - 1
    17. {
    18. printf("front=%d,rear=%d\n",front, rear);
    19. printf("队列已满,入队失败\n");
    20. return;
    21. }
    22. else if (IsEmpty() == 1)//如果队列是空的
    23. {
    24. //我们可以把索引值0的位置加入队列,现在我们把x写入索引值是rear的位置,因为我们要插入一个元素,所以rear\front要加1变为0
    25. front = 0;
    26. rear = 0;
    27. A[rear] = x;
    28. printf("入队成功:队首值Front=%d\n", Front());
    29. printf("front=%d,rear=%d\n", front, rear);
    30. }
    31. else
    32. {
    33. rear =(rear +1 )%N;//原来这里不是循环的时候是rear=rear+1
    34. A[rear] = x;
    35. printf("front=%d,rear=%d\n", front, rear);
    36. }
    37. printf("入队成功:队首值A[%d]=%d,队尾值是:A[%d]=%d\n", front, Front(), rear,A[rear]);
    38. }
    39. void DeQueue() {
    40. if (IsEmpty() == 1)//如果队列为空,我们无法从中移出一个元素
    41. {
    42. printf("无法移出:");
    43. printf("front=%d,rear=%d\n", front, rear);
    44. return;
    45. }
    46. else if (front == rear)//队列中只有一个元素
    47. {
    48. //这时front和rear不是-1而是相等,把最后一个元素删除的同时,把front和rear同时设置为-1,DeQueue函数会让队列变空,为了把队列变空,front = rear=-1
    49. printf("队列只有一个元素,删除的元素为:%d\n", Front());
    50. A[front] = 0;
    51. front =-1;
    52. rear = -1;
    53. printf("front=%d,rear=%d\n", front, rear);
    54. }
    55. else
    56. {
    57. //使用循环数组
    58. A[front] = 0;//这段代码的意思是我们每次删除队头就将它的值置为0
    59. printf("出队成功:队首值A[%d]=%d,队尾值是:A[%d]=%d\n", front, Front(), rear, A[rear]);
    60. front =(front + 1)%N;//因为我们之前约定的是从对头删除,从队尾插入 front = front + 1
    61. printf("front=%d,rear=%d\n", front, rear);
    62. }
    63. }

    查询队列信息的函数

    1. void show(void) {
    2. if((front == 1)&&(rear==1))
    3. {
    4. printf("该队列长度为1,剩余长度为9\n");
    5. }
    6. else if ((front == -1 )&&( rear == -1))
    7. {
    8. printf("该队列长度为%d\n", N);
    9. printf("剩余长度为%d\n", N );
    10. }
    11. else if(rear>front)//这里保证是入队
    12. {
    13. printf("该队列长度为%d\n", abs(front - rear)+1);
    14. printf("剩余长度为%d\n", N - abs(front - rear)-1);
    15. }
    16. else //这里保证是出队
    17. {
    18. printf("该队列长度为%d\n", abs(front - rear) );
    19. printf("剩余长度为%d\n", N - abs(front - rear) );
    20. }
    21. }

    全部代码

    1. #include
    2. #include
    3. #include//为bool类型增加的头文件
    4. /*
    5. EnQueue(x)
    6. DeQueue(x)
    7. front()
    8. IsEmpty()
    9. //这四个函数时间复杂度是O(1)orConstant time
    10. 我们是用循环数组来实现的
    11. */
    12. int front = -1;//队尾
    13. int rear = -1;//对头
    14. int A[10];//我们定义一个数组来实现队列
    15. //数组的长度为N,N=10
    16. int N=10;
    17. int Front(void) {
    18. //检查队列是否为空,只有front不为-1的时候才返回A[front]
    19. return A[front];
    20. }
    21. bool IsEmpty(void) {
    22. if ((front == -1) && (rear == -1))//表示队列为空,front==rear 要么为空,要么为一个元素;
    23. return 1;
    24. else
    25. return 0;
    26. }
    27. void EnQueue(int x) {//调用完EnQueue之后的队列,front和rear是一样的
    28. if ((rear+1)%N==front)//如果rear已经等于数组A的最大索引值,我们就不能插入元素了//rear == sizeof(A) - 1
    29. {
    30. printf("front=%d,rear=%d\n",front, rear);
    31. printf("队列已满,入队失败\n");
    32. return;
    33. }
    34. else if (IsEmpty() == 1)//如果队列是空的
    35. {
    36. //我们可以把索引值0的位置加入队列,现在我们把x写入索引值是rear的位置,因为我们要插入一个元素,所以rear\front要加1变为0
    37. front = 0;
    38. rear = 0;
    39. A[rear] = x;
    40. printf("入队成功:队首值Front=%d\n", Front());
    41. printf("front=%d,rear=%d\n", front, rear);
    42. }
    43. else
    44. {
    45. rear =(rear +1 )%N;//原来这里不是循环的时候是rear=rear+1
    46. A[rear] = x;
    47. printf("front=%d,rear=%d\n", front, rear);
    48. }
    49. printf("入队成功:队首值A[%d]=%d,队尾值是:A[%d]=%d\n", front, Front(), rear,A[rear]);
    50. }
    51. void DeQueue() {
    52. if (IsEmpty() == 1)//如果队列为空,我们无法从中移出一个元素
    53. {
    54. printf("无法移出:");
    55. printf("front=%d,rear=%d\n", front, rear);
    56. return;
    57. }
    58. else if (front == rear)//队列中只有一个元素
    59. {
    60. //这时front和rear不是-1而是相等,把最后一个元素删除的同时,把front和rear同时设置为-1,DeQueue函数会让队列变空,为了把队列变空,front = rear=-1
    61. printf("队列只有一个元素,删除的元素为:%d\n", Front());
    62. A[front] = 0;
    63. front =-1;
    64. rear = -1;
    65. printf("front=%d,rear=%d\n", front, rear);
    66. }
    67. else
    68. {
    69. //使用循环数组
    70. A[front] = 0;
    71. printf("出队成功:队首值A[%d]=%d,队尾值是:A[%d]=%d\n", front, Front(), rear, A[rear]);
    72. front =(front + 1)%N;//因为我们之前约定的是从对头删除,从队尾插入 front = front + 1
    73. printf("front=%d,rear=%d\n", front, rear);
    74. }
    75. }
    76. /*
    77. 循环数组,当我们遍历一个数组时,我们可以把它想象成是没有结尾的,
    78. 最后到达最大索引位置
    79. 对于一个循环数组来说,当前位置为i,下一个索引的不是简单的i+1,而是(i+1)%N;N为数组元素的个数
    80. i不等于N-1,取模操作并不会有什么影响;但是i=N-1下一个位置将会是0,取余等于0;循环数组的前一个位置
    81. 将是(i+N-1)%N;我们可以直接是(i-1)%N,但是为了确保括号表达式是一个正数,我们加上了N
    82. */
    83. void show(void) {
    84. if((front == 1)&&(rear==1))
    85. {
    86. printf("该队列长度为1,剩余长度为9\n");
    87. }
    88. else if ((front == -1 )&&( rear == -1))
    89. {
    90. printf("该队列长度为%d\n", N);
    91. printf("剩余长度为%d\n", N );
    92. }
    93. else if(rear>front)//这里保证是入队
    94. {
    95. printf("该队列长度为%d\n", abs(front - rear)+1);
    96. printf("剩余长度为%d\n", N - abs(front - rear)-1);
    97. }
    98. else //这里保证是出队
    99. {
    100. printf("该队列长度为%d\n", abs(front - rear) );
    101. printf("剩余长度为%d\n", N - abs(front - rear) );
    102. }
    103. }
    104. int main()
    105. {
    106. /*
    107. 队列的出队和入队就是通过这两个变量来实现的
    108. 增加rear,相当于插入数字
    109. 增加front,相当于删除数字
    110. 对于一个空队列来说,front和rear都是-1,可以通过检查这两个的值来判断是不是空队列
    111. */
    112. EnQueue(2);
    113. EnQueue(5);
    114. EnQueue(4);
    115. EnQueue(8);
    116. EnQueue(0);
    117. EnQueue(1);
    118. EnQueue(3);
    119. EnQueue(1);
    120. EnQueue(3);
    121. EnQueue(1);
    122. show();
    123. for (int i = 0; i < 10; i++)
    124. {
    125. printf("A[%d]=%d\n", i, A[i]);
    126. }
    127. EnQueue(12);
    128. DeQueue();
    129. DeQueue();
    130. DeQueue();
    131. DeQueue();
    132. DeQueue();
    133. DeQueue();
    134. DeQueue();
    135. DeQueue();
    136. DeQueue();
    137. DeQueue();
    138. DeQueue();
    139. show();
    140. for (int i = 0; i < 10; i++)
    141. {
    142. printf("A[%d]=%d\n", i, A[i]);
    143. }
    144. return 0;
    145. }

    代码验证

     可能大家会觉得上面的代码太过于冗长,我们给出下面的简洁版代码

     

    1. #include
    2. #include
    3. #include//为bool类型增加的头文件
    4. int A[5];
    5. int N = 5;
    6. int rear = -1;
    7. int front = -1;
    8. int Front_value() {
    9. return A[front];
    10. }
    11. bool IsEmpty(void) {
    12. if ((rear == -1) && (front == -1))
    13. return 1;
    14. else
    15. return 0;
    16. }
    17. void Enqueue(int x) {
    18. if ((rear + 1) % N == front) {
    19. printf("队列已满,无法入队\n");
    20. return;
    21. }
    22. else if (IsEmpty()==1) {
    23. //这种情况是队列是空
    24. rear = 0;
    25. front = 0;
    26. A[rear] = x;
    27. printf("入队成功:队首值A[%d]=%d\n", front, Front_value());
    28. printf("front=%d,rear=%d\n", front, rear);
    29. }
    30. else {
    31. //这个就是不断移动队尾的值,因为是从队尾移动
    32. rear = (rear + 1) % N;
    33. A[rear] = x;
    34. printf("front=%d,rear=%d\n", front, rear);
    35. }
    36. printf("对首值A[%d] =%d,队尾值:A[%d] =%d,front=%d\n", front, Front_value(),rear, A[rear], front);
    37. }
    38. void Dequeue(void) {
    39. if (IsEmpty() == 1) {
    40. printf("队列为空,无法出队\n");
    41. return;
    42. }
    43. else if (rear ==front) {
    44. //这里必须要要rear ==front这样子写,如果是写成rear==0&&front==0,当对为空时,任然会执行rear==0这一个操作,就会出现问题
    45. //队列只有一个元素,从队头开始删除
    46. A[front] = 0;//把唯一的元素置为0
    47. rear = -1;
    48. front = -1;
    49. printf("front=%d,rear=%d\n", front, rear);
    50. }
    51. else {
    52. A[front] = 0;
    53. printf("对首值A[%d] =%d,队尾值:A[%d] =%d,front=%d\n", front, Front_value(), rear, A[rear], front);
    54. printf("front=%d,rear=%d\n", front, rear);
    55. front = (front + 1) % N;
    56. }
    57. }
    58. int main(void) {
    59. Enqueue(5);
    60. Enqueue(4);
    61. Enqueue(3);
    62. Enqueue(2);
    63. Enqueue(1);
    64. Enqueue(7);
    65. for (int i = 0; i < 5; i++)
    66. {
    67. printf("A[%d] =%d ",i, A[i]);
    68. }
    69. printf("\n");
    70. Dequeue();
    71. Dequeue();
    72. Dequeue();
    73. Dequeue();
    74. Dequeue();
    75. Dequeue();
    76. Dequeue();
    77. for (int i = 0; i < 5; i++)
    78. {
    79. printf("A[%d] =%d ", i, A[i]);
    80. }
    81. printf("\n");
    82. return 0;
    83. }

     

  • 相关阅读:
    【js&three.js】全景vr看房进阶版
    TOPS是每秒一万亿次操作
    java毕业生设计校园教育服务平台计算机源码+系统+mysql+调试部署+lw
    聚观早报 | 苏宁易购入驻美团外卖;今日头条接入抖音电商
    边缘路由器和普通路由器哪个好 边缘路由器跟路由器有什么区别
    [SpringBoot]配置文件①(配置文件格式、yaml配置及读取)
    c++文件的打开、读写和关闭。缓冲区的使用和控制。
    oracle事物处理语言—TCL
    【基础恶补】JavaScript数组的一些方法,reduce,filter,reverse,map等
    盲盒商城系统玩法大讲坛
  • 原文地址:https://blog.csdn.net/Abcd_cnom/article/details/133420015