一、栈
1.栈的定义
栈是仅限在表尾进行插入和删除的线性表;栈遵循先进先出原则(LIFO:Last In First Out);栈的两个基本操作,进栈和出栈进栈元素只能插入表尾,出栈也只能弹出表尾一个元素;
2.栈的代码结构
可以把栈的元素看做一个链表,StackNode可以看做这个栈链表的每一个节点结构,LinkStack则可以看做该链表的头结点,top为头指针,count为链表长度;
typedef struct StackNode {
int data;
struct StackNode* next;
}Node;
typedef struct LinkStack {
Node* top;
int count;
}Stack;
3.进栈操作
构建一个新的节点,指针域指向栈顶元素,newNode->next = stack.top;再让头指针指向新栈顶,stack.top = newNode;栈的长度加一,stack.count++;
void Push(Stack &stack, int data) {
Node *newNode = (Node*)malloc(sizeof(Node));
newNode->data = data;
newNode->next = stack.top;
stack.top = newNode;
stack.count++;
cout << "成功将数据" << data << "入栈!" << endl;
}
4.出栈操作
x先判断栈是否为空,然后让popNode获取栈顶节点,将top指针指向下一元素(新栈顶);再释放老栈顶,栈长度减一;
void Pop(Stack &stack, int &data) {
if(Empty(stack)) {
return;
}
data = stack.top->data;
Node* popNode;
popNode = stack.top;
stack.top = stack.top->next;
free(popNode);
stack.count--;
cout << "成功将数据" << data << "弹出!" << endl;
}
5.测试代码
#include<iostream>
#include<cstdlib>
using namespace std;
typedef struct StackNode {
int data;
struct StackNode* next;
}Node;
typedef struct LinkStack {
Node* top;
int count;
}Stack;
bool Empty(Stack &stack) {
if(!stack.count) {
cout << "空栈!" << endl;
return true;
}
return false;
}
void Push(Stack &stack, int data) {
Node *newNode = (Node*)malloc(sizeof(Node));
newNode->data = data;
newNode->next = stack.top;
stack.top = newNode;
stack.count++;
cout << "成功将数据" << data << "入栈!" << endl;
}
void Pop(Stack &stack, int &data) {
if(Empty(stack)) {
return;
}
data = stack.top->data;
Node* popNode;
popNode = stack.top;
stack.top = stack.top->next;
free(popNode);
stack.count--;
cout << "成功将数据" << data << "弹出!" << endl;
}
int main() {
Stack stack;
stack.count = 0;
stack.top = NULL;
Empty(stack);
Push(stack, 1);
Push(stack, 2);
int data = 0;
while(stack.count) {
Pop(stack, data);
}
getchar();
return 0;
}
二、队列
1.队列的定义
队列是只允许从一端进行插入操作,从另一端进行删除操作的线性表;是一种先进先出的线性表(FIFO:First In First Out);出入端为队尾,删除端为队头;
2.队列的代码结构
和栈类似,有节点的结构体和队列属性结构体,队列有一个头结点和一个尾指针,注意,一个头结点一个尾指针;
typedef struct QueueNode {
int data;
struct QueueNode* next;
}Node;
typedef struct LinkQueue {
Node *front, *rear;
}Queue;
3.入队操作
等同于在链表尾部插入节点;尾节点的指针域指向新构建节点,然后再让尾指针指向新的尾结点;
void InQueue(Queue &queue, int data) {
Node* newNode = (Node*)malloc(sizeof(Node));
newNode->data = data;
newNode->next = NULL;
queue.rear->next = newNode;
queue.rear = newNode;
cout << data << "成功入队!" << endl;
}
4.出队操作
出队操作就是头结点的后继节点出队;先判断队列是否为空,当尾指针指向头结点时,说明队列空了;如果不为空,那么将出队列节点断开链接;如果出队节点正好是尾结点,那么将尾指针指向头结点,队列空了;
void OutQueue(Queue &queue, int &data) {
Node* outNode;
if(queue.front == queue.rear) {
cout << "空队列!" << endl;
return;
}
outNode = queue.front->next;
data = outNode->data;
queue.front->next = outNode->next;
if(outNode == queue.rear) {
queue.rear = queue.front;
}
free(outNode);
cout << data << "成功出队!" << endl;
}
5.测试代码
#include<iostream>
#include<cstdlib>
using namespace std;
typedef struct QueueNode {
int data;
struct QueueNode* next;
}Node;
typedef struct LinkQueue {
Node *front, *rear;
}Queue;
void InQueue(Queue &queue, int data) {
Node* newNode = (Node*)malloc(sizeof(Node));
newNode->data = data;
newNode->next = NULL;
queue.rear->next = newNode;
queue.rear = newNode;
cout << data << "成功入队!" << endl;
}
void OutQueue(Queue &queue, int &data) {
Node* outNode;
if(queue.front == queue.rear) {
cout << "空队列!" << endl;
return;
}
outNode = queue.front->next;
data = outNode->data;
queue.front->next = outNode->next;
if(outNode == queue.rear) {
queue.rear = queue.front;
}
free(outNode);
cout << data << "成功出队!" << endl;
}
int main() {
Queue queue;
queue.rear = queue.front;
int data = 0;
OutQueue(queue, data);
InQueue(queue, 1);
InQueue(queue, 2);
OutQueue(queue, data);
OutQueue(queue, data);
getchar();
return 0;
}
三、总结
其实栈和队列的链式存储方式就是链表的改型,操作其实和链表的基本操作没什么区别,无非就是插入和删除节点;当然栈和队列也有顺序存储结构,队列也还有循环队列等一些特殊结构,后面再做总结;这两种数据结构有其鲜明的结构特点,栈的先进后出,队列的先进先出,都能在特定的数据处理场景下大放光彩;这两种数据结构也相对比较简单,算是线性表的一种扩展结构;