栈与队列
具有的操作:
- 初始化栈(队列)
- 判断栈(队列)是否为空
- 判断栈(队列)是否已满
- 入栈(队列)
- 出栈(队列)
- 遍历栈(队列)
栈满足的特性
- 先进后出 后进先出
队列满足的特性
- 先进先出,后进后出
顺序栈(数组形式)
-
定义数据类型 默认以int类型为主,可以使用模板封装任意类型的栈
//存int类型数据的顺序栈 int* pStack; //指向栈的指针 int size; //存储栈中的元素个数
-
栈的操作
//初始化栈 void InitStack(); //入栈 void push(int data); //出栈 void pop(); //判断栈是否为空 bool isEmpty(); //获取栈顶元素,只能获取栈顶元素 int getTop(); //遍历元素 void _travel();
-
初始化栈
//初始化栈 void InitStack() { pStack = NULL; }
-
入栈操作: 分两种方式
-
当栈为空的时候,
void push() { if (pStack == NULL) { //1. 开辟新的空间 pNew = (int*)malloc(sizeof(int)* (size+1)); //2. 原来的内存指向新的开辟的内存 pStack = pNew; //3. 插入数据 pStack[size++] = data; }
-
当栈不为空的时候
- 即需要在数组的最后添加元素,首先要开辟一块新的内存区域,在新开辟的空间进行数组元素的增加
//栈不为空 操作步骤: else { //1.为后面的开辟新的内存 int* pNew = (int*)malloc(sizeof(int) * (size + 1)); //2.将原有的内存数据的元素拷贝到新的内存里 memcpy(pNew, pStack, sizeof(int) * size); //3.释放原有的内存空间 free(pStack); //4.原来的内存指向新的开辟的内存 pStack = pNew; //5.插入数据 pStack[size++] = data; }
-
-
出栈操作
-
对于栈,先进的元素后出,后进的元素先出,即首先删除数组末尾的元素,然后依次往前删除
void pop() { if (isempty()) { printf("栈为空\n"); return; } int* pNew = (int*)malloc(sizeof(int) * (size - 1)); memcpy(pNew, pStack, sizeof(int) * (size - 1)); free(pStack); pStack = pNew; size--; }
-
-
栈的其他操作
//判断栈是否为空 bool isEmpty() { return (size == 0); } //获取栈顶元素,只能获取栈顶元素 int getTop() { return pStack[size-1]; } //遍历元素 void _travel() { printf("size(%d):", size); for (int i = 0; i < size; i++) { printf("%d ", pStack[i]); } printf("\n"); }
-
栈的测试
int main() { InitStack(); //测试 for (int i = 5; i < 15; i++) { push(i); _travel(); } while (!isEmpty()) { printf("当前栈顶:%d\n", getTop()); pop(); //出栈 } return 0; }
顺序队列(数组形式)
-
队列的操作与栈基本一致 只有出队的时候与出栈不同
-
队列先进先出 后进后出 先删除数组的第一个元素,在依次往后删除数组元素
-
出队
//出队 int pop() { if (isEmpty()) { printf("队列为空,出队失败\n"); return -1; } /* 队列: 先进先出 要删除第一个元素 */ //释放第一个元素 int ret = pQueue[0]; //1. 开辟一个新的内存段 int* pNew = (int*)malloc(sizeof(int) * (size - 1)); //2. 原有内存段的数据拷贝到新的内存段 要删除第一个 旧的内存区块跳过第一个元素 memcpy(pNew, pQueue + 1, sizeof(int) * (size - 1)); //3. 释放原有的内存段 free(pQueue); //4. 原有的内存段指向新开辟的内存 pQueue = pNew; //5. size减少 size--; //6. 返回每次释放的元素 return ret; }
-
队列测试
int main()
{
InitQueue();
//测试
for (int i = 5; i < 15; i++)
{
push(i);
_travel();
}
int ret = 0;
while (ret != -1)
{
printf("队列顶:%d\n", ret = pop());
}
return 0;
}
``
链式栈 (无头节点)
链表的形式存储栈的节点 操作和链表的操作基本一致
-
这里以结构体类型描述栈的结构
//栈节点的数据类型 struct Student { char name[50]; int age; float score; }; typedef struct Student STU; #define STU_SIZE sizeof(struct Student) //存储链式栈的链表 struct List { STU data; struct List* next; }; typedef struct List Node;
-
链式栈的操作
//创建节点 Node* CreateNode(STU* data); //尾插法 入栈 void push(Node** pHead,STU* data); //出栈 Node* pop(Node** pHead); //遍历栈 void travel(Node* head); //打印 void Printf(STU* p);
-
创建栈节点
//创建节点 Node* CreateNode(STU* data) { Node* pNew = (Node*)malloc(sizeof(Node)); if (pNew == NULL) { printf("创建失败\n"); return 0; } strcpy(pNew->data.name, data->name); pNew->data.age = data->age; pNew->data.score = data->score; pNew->next = NULL; //返回节点 return pNew; }
-
入栈 链表的尾插法入栈
- 分两种情况,看他是空链表还是非空链表
//尾插法 入栈 void push(Node** pHead, STU* data) { if (pHead == NULL) { return; } //创建新的节点 Node* pNew = CreateNode(data); //空链表 新节点要成为当前节点的第一个几点 if (*pHead == NULL) { *pHead = pNew; } else { //找到链表的尾部 插入节点 Node* pTemp = *pHead; while (pTemp->next) { pTemp = pTemp->next; } //在尾部插入 pTemp->next = pNew; } }
-
出栈
- 删除链表的最后一个节点,依次往前删除
//出栈 删除末尾节点 Node* pop(Node** pHead) { if (pHead == NULL || *pHead == NULL) { return NULL; } //找到链表的最后一个节点 Node* pTail = *pHead; while (pTail->next) { pTail = pTail->next; } //1. 如果链表只有一个节点,第一个就等于末尾节点 if (pTail == *pHead) { *pHead = NULL; } //2. 如果有多个节点 找到最后一个的前一个并且删除最后一个 else { Node* pPreTail = *pHead; while (pPreTail->next != pTail) { pPreTail = pPreTail->next; } //最后一个节点的前一个节点next置空 实现删除最后一个 pPreTail->next = NULL; } return pTail; }
-
遍历及打印
//遍历栈 void travel(Node* pHead) { if (pHead == NULL) { printf("栈为空\n"); return; } Node* pTemp = pHead; while (pTemp) { //传入地址 Printf(&(pTemp->data)); pTemp = pTemp->next; } } //打印 void Printf(STU* p) { printf("姓名:%s 年龄:%d 成绩:%.2f\n", p->name, p->age, p->score); }
-
链式栈测试
int main() { STU info[5] = { {"关羽",55,55.55}, {"张飞",44,44.44}, {"赵云",33,33.33}, {"马超",22,22.22}, {"黄忠",11,11.11}, }; Node* pHead = NULL; //入栈 for (int i = 0; i < 5; i++) { push(&pHead, &info[i]); } travel(pHead); printf("\n\n"); //出栈 Node* pStackTemp = NULL; while (1) { pStackTemp = pop(&pHead); if (pStackTemp == NULL) { printf("出栈失败\n"); break; } Printf(&pStackTemp->data); //释放内存 free(pStackTemp); printf("\n\n"); } return 0; }
链式队列(无头节点)
- 操作和链式栈基本一致,除了出栈和出队
- 出队: 先进先出 后进后出 先删除首元节点,再依次往后删除节点
//出队 删除头节点
Node* pop(Node** pHead)
{
if (pHead == NULL || *pHead == NULL)
{
printf("出队失败\n");
return NULL;
}
Node* pTemp = *pHead;
//只有一个节点
if (( * pHead)->next == NULL)
{
*pHead = NULL;
}
else
{
//有多个节点,则跳过第一个
*pHead = ( * pHead)->next;
}
return pTemp;
}