链表代码的逻辑思路
记得要自己尝试着敲一遍,不然等于没看!
头插法
数据结构
struct Node
{
int data;
struct Node* next; //表示下一节点
};
- 创建链表时,申请malloc头节点,并且头节点的next域为空。
//创建链表
struct Node* createList()
{
//向内存申请空间
struct Node* headNode = (struct Node*)malloc(sizeof(struct Node));
//指向空
headNode->next = NULL;
return headNode;
}
- 创建结点时,需要传入数据,由于只是单纯的创建结点,其指针域直接指向Null
//创建结点(要插入数据)
struct Node* createNode(int data)
{
struct Node* newNode = (struct Node*)malloc(sizeof(struct Node));
//插入数据
newNode->data =data;
//注意,不是插入结点,是创建结点,所以指向空
newNode->next = NULL;
return newNode;
}
- 然后是打印链表中的值,只需要使用while循环将结点打印后,移动到下一节点即可。
//打印结点
void printList(struct Node* headNode) {
//头节点默认不打印,所以直接指向下一个结点
struct Node* pMove = headNode->next;
while (pMove)
{
printf("%d", pMove->data);
//移动下一个结点
pMove = pMove->next;
}
printf("\n");
}
- 插入一个新节点,首先要传入链表以及数据,然后插入方法中调用创建结点方法,然后将得到的新节点插入链表中,注意:这里使用的是头插法,所以先让新节点指针指向头节点的next域,再让头节点的next指针指向新节点,这里的顺序不能颠倒。
//插入结点(头插法)
void insertNode(struct Node* headNode, int data) {
//创建要插入的结点
struct Node* newNode = createNode(data);
//首先让新节点的next指针 指向头节点的下一个结点
newNode->next = headNode->next;
//然后再让头节点的next指针指向新节点
headNode->next = newNode;
}
- 删除结点方法,首先是传入链表以及传入的目标结点值,由于链表删除是需要两个结点的,所以要声明两个结点,分为:当前结点和当前结点的前一个结点,删除的方法很简单,即将前一个结点的指针跳跃式跳过目标删除结点指向下一个即可。
//删除指定结点
void deleteNode(struct Node* headNode,int posData){
//目标结点指向头节点的下一个位置
struct Node* posNode = headNode->next;
//充当目标结点的前一个位置
struct Node* posNodeFront = headNode;
if (posNode==NULL)
{
printf("无法删除链表,链表为空\n");
}
else {
//循环匹配找到目标结点
while (posNode->data!=posData)
{
//下面两行的代码表示的是移动位置。
posNodeFront = posNode;
//移动到下一个位置
posNode = posNode->next;
}
//如果循环找到了目标结点,则让前一个结点指向目标删除结点的后一个结点
posNodeFront->next = posNode->next;
//删除结点
free(posNode);
}
}
队列的代码逻辑思路
循环队列
循环队列是用于解决浪费传统队列所带来的空间浪费问题,所以运用到一种取余操作,使得其位置能重新回到队首。
结构体
#define MaxSize 5 //定义最大值
// 循环队列
struct SqQueue
{
int data[MaxSize];
int front, rear;// 队头、队尾指针
};
初始化队列
默认情况下队列为空,则队头、队尾指针指向同一个位置
//初始化队列
//默认情况下队列为空,则队头、队尾指针指向同一个位置
void InitQueue(SqQueue &Q) {
Q.front = 0;
Q.rear = 0;
printf("初始化队列成功!\n");
}
判断是否为空
即判断头指针和尾指针是否在同一个位置。
//判断是否为空
int IsEmpty(SqQueue &Q) {
if(Q.front==Q.rear){
return 1;
}
else
{
return 0;
}
}
入队操作
用取余的操作来判断队列是否为满,并且空余一个空间来做判断。
//循环队列入队操作
int EnQueue(SqQueue &Q,int x){
//循环队列在入队时,要判断是否为满
//由于循环队列的特殊性,所以需要空余一个空间出来,以判断队列为满
//即rear+1时,位置是否和front一致
if ((Q.rear+1)%MaxSize==Q.front) {
printf("队列已满!\n");
return 0;
}
//当前位置存放数据
Q.data[Q.rear] = x;
//尾指针位置+1(取余操作)
Q.rear = (Q.rear + 1) % MaxSize;
return 1;
}
出队操作
//出队操作(首先判断是否为空)
int DeQueue(SqQueue &Q,int x){
if(IsEmpty(Q)){
printf("队列为空!\n");
return 0;
}
else
{
x = Q.data[Q.front];
Q.front = (Q.front + 1) % MaxSize;
return 1;
}
}
主函数
int main() {
SqQueue Q;
InitQueue(Q);
EnQueue(Q, 1);
EnQueue(Q, 2);
EnQueue(Q, 3);
EnQueue(Q, 4);
EnQueue(Q, 5);
PrintQueue(Q);
}
栈的代码逻辑思路
![[Pasted image 20230918202731.png]]
初始化栈
初始化栈时,top指针默认指向-1,即表示栈为空
//初始化队列
void InitStack(Stack &stack) {
stack.top = -1;
printf("初始化成功!\n");
}
入栈Push
入栈时,先将指针上移再赋值
//入栈
int Push(Stack &stack,int x) {
//判断栈是否满
if (stack.top==MaxSize-1) {
printf("栈已满!无法入栈!");
return 0;
}
//入栈
stack.top++;
stack.data[stack.top] = x;
return 1;
}
出栈操作Pop
出栈时,先赋值再出栈
//出栈
int Pop(Stack &stack,int x) {
//判断栈是否为空
if (stack.top==-1)
{
printf("栈为空!无法出队!");
return 0;
}
x = stack.data[stack.top];
stack.top--;
return 1;
}
查看栈顶元素
//查看栈顶元素的值
int GetTop(Stack s,int &x) {
x = s.data[s.top];
return 1;
}
主函数
int main() {
Stack s;
int x;
InitStack(s);
Push(s,1);
Push(s,2);
Push(s,3);
Push(s,4);
Push(s,5);
GetTop(s, x);
printf("%d\n",x);
Pop(s,x);
GetTop(s, x);
printf("%d\n", x);
}