目录
栈需要定义位置元素指向栈顶,通过栈顶后进先出。
队列需要定义队首和对位元素,注意出栈入栈后队首和队尾的指向不要超过最大长度。
单链表真题2019-41![](https://img-blog.csdnimg.cn/direct/b6d44cc62b0b4910abfcc18052164918.png)
解题设计:
- 如何找到链表的中间结点、
- 后一半链表设置为L2,如何让L2原地逆置。
- 将L与L2链表合并,合并时轮流放入一个结点。
#include <stdio.h>
#include <stdlib.h>
typedef int ElemType;
typedef struct node {
ElemType data;
struct node *next;
} NODE;
void LinkTail(NODE *&L) {
L = (NODE *) malloc(sizeof(NODE));
L->next = NULL;
ElemType elem;
NODE *r = L, *p;
scanf("%d", &elem);
while (elem != 9999) {
p = (NODE *) malloc(sizeof(NODE));
p->data = elem;
r->next = p;
r = p;
scanf("%d", &elem);
}
r->next = NULL;
}
//找到中间节点,并设置好L2
NODE *FindMiddle(NODE *L, NODE *&L2) {
L2 = (NODE *) malloc(sizeof(NODE));
NODE *pcur, *ppre;//双指针法。双指针遍历是考研常考点
pcur = ppre = L->next;
while (pcur) {
pcur = pcur->next;
if (NULL == pcur || NULL == pcur->next) break;
pcur = pcur->next;
ppre = ppre->next;
}
L2->next = ppre->next;
ppre->next = NULL;
}
void Reverse(NODE *L2) {
NODE *r, *s, *t;
r = L2->next;
if (NULL == r || NULL == r->next)return;//链表无结点或只有一个结点直接返回
s = r->next;
t = s->next;
while (NULL != t) {//逆置
s->next = r;
r = s;
s = t;
t = t->next;
}
s->next = r;
L2->next->next = NULL;//L2头结点next第一个结点next=NULL
L2->next = s;
}
void Merge(NODE *L, NODE *L2) {
NODE *mid, *p, *p2;
mid = L->next;//mid始终指向新列表的表尾
p = mid->next, p2 = L2->next;
if (NULL == p2)return;
while (NULL != p) {
mid->next = p2;
mid = mid->next;
p2 = p2->next;
mid->next = p;
mid = mid->next;
p = p->next;
}
if (NULL != p2){
mid->next = p2;
mid = mid->next;
}
mid->next=NULL;
}
void PrintLink(NODE *L) {
while (L->next != NULL) {
printf("%3d", L->next->data);
L = L->next;
}
printf("\n");
}
int main() {
NODE *L;
LinkTail(L);
//寻找中间结点
NODE *L2 = NULL;
FindMiddle(L, L2);
Reverse(L2);
Merge(L, L2);
PrintLink(L);
return 0;
}
FindMiddle、Reverse、Merge函数的循环次数均为n/2,总运行次数是1.5n,因此整个程序的时间复杂度为O(n)。
栈
OJ单链表查找、增加、删除
输入3 4 5 6 7 9999一串整数,9999代表结束,通过尾插法新建链表,查找第二个位置的值并输出,在2个位置插入99,输出为 3 99 4 5 6 7,删除第4个位置的值,打印输出为 3 99 4 6 7。
#include <stdio.h>
#include <stdlib.h>
typedef struct Node {
int data;
struct Node *next;
} Node, *NodeLink;
void TailLink(NodeLink &L) {
L = (NodeLink) malloc(sizeof(Node));
L->next = NULL;
NodeLink pcur, pmid;
pcur = L;
int x;
scanf("%d", &x);
while (9999 != x) {
pmid = (NodeLink) malloc(sizeof(Node));
pmid->data = x;
pcur->next = pmid;
pcur = pmid;
scanf("%d", &x);
}
pcur->next = NULL;
}
NodeLink FindNode(NodeLink L, int i) {
if (i < 0) return NULL;
for (int j = 1; j <= i && NULL != L; j++) {
L = L->next;
}
return L;
}
bool InsertNode(NodeLink L, int i, int val) {
NodeLink pper = FindNode(L, i - 1);
if (NULL == pper) return false;
NodeLink p = (NodeLink) malloc(sizeof(Node));
p->data = val;
p->next = pper->next;
pper->next = p;
return true;
}
bool DeleteNode(NodeLink L) {
NodeLink pper = FindNode(L, 3);
if (NULL == pper || NULL == pper->next)return false;
NodeLink p = pper->next;
pper->next = p->next;
free(p);
p = NULL;
return true;
}
void PrintLink(NodeLink L) {
L = L->next;
while (NULL != L) {
printf("%3d", L->data);
L = L->next;
}
printf("\n");
}
int main() {
NodeLink L;
TailLink(L);
NodeLink ptwo = FindNode(L, 2);
if (ptwo)printf("%d\n", ptwo->data);
InsertNode(L, 2, 99);
PrintLink(L);
DeleteNode(L);
PrintLink(L);
return 0;
}
栈的原理解析
栈中元素先进后出,最先入栈为栈底,最后入栈为栈顶。
链栈了解即可。
出栈并不会改变元素,而是改变top的栈顶指向 。
栈初始化、入栈、出栈
#include <stdio.h>
#include <stdlib.h>
#define MaxSize 50
typedef int ElemType;
typedef struct {
ElemType data[MaxSize];//数组
int top;//始终指向栈顶位置的变量
} SqStack;
void InitStack(SqStack &S) {
S.top = -1;//初始化栈,即S.top=-1栈为空
}
bool StackEmpty(SqStack S) {
if (-1 == S.top) return true;
else return false;
}
//入栈
bool Push(SqStack &S, ElemType x) {
//判断栈是否满了
if (MaxSize - 1 == S.top) {
return false;
}
S.data[++S.top] = x;
return true;
}
//获取栈顶元素
bool GetTop(SqStack S, ElemType &m) {
if (StackEmpty(S))return false;
m = S.data[S.top];
return true;
}
//弹栈
bool Pop(SqStack &S,ElemType &m){
if (StackEmpty(S))return false;
m=S.data[S.top--];//出栈
return true;
}
int main() {
SqStack S;
InitStack(S);
bool flag;
flag = StackEmpty(S);
if (flag) printf("Stack is empty\n");
Push(S, 3);
Push(S, 4);
Push(S, 5);
ElemType m;
flag = GetTop(S, m);
if (flag) printf("Get top %d\n", m);
flag = Pop(S,m);
if(flag) printf("pop element %d\n",m);
return 0;
}
队列
简称队,是一种操作受限的线性表。只允许在对首(Front)进行插入(入队或进队),队尾(Rear)进行删除(出队或离队)。FIFO(first in first out)
循环队列
存储个数为MaxSize-1个,(Q.rear+1)%MaxSize==Q.front以判断循环队列满队。
循环队列实现
#include <stdio.h>
#include <stdlib.h>
#define MaxSize 5
typedef int ElemType;
typedef struct {
ElemType data[MaxSize];
int front, rear;
} SqQueue;
void InitQueue(SqQueue &Q) {
Q.front = Q.rear = 0;//初始化循环队列,让队首和队尾都指向0
}
bool IsEmpty(SqQueue Q) {
return (Q.rear == Q.front);
}
//入队
bool EnQueue(SqQueue &Q, ElemType x) {
if (Q.front == (Q.rear + 1) % MaxSize)return false;//判断循环队列是否满队
Q.data[Q.rear] = x;//放入元素
Q.rear = (Q.rear + 1) % MaxSize;//rear后移,同时让rear在MaxSize范围内
return true;
}
//出队
bool DeQueue(SqQueue &Q, ElemType &x) {
if (IsEmpty(Q)) return false;//空队列无法出队
x = Q.data[Q.front];//出队
Q.front = (Q.front + 1) % MaxSize;
return true;
}
int main() {
SqQueue Q;
InitQueue(Q);
bool ret;
ret = IsEmpty(Q);
if (ret) printf("SqQueue is empty\n");
else printf("SqQueue is not empty\n");
EnQueue(Q, 3);
EnQueue(Q, 4);
EnQueue(Q, 5);
ret = EnQueue(Q, 6);
ret = EnQueue(Q, 7);
if (ret)printf("EnQueue Successfully\n");
else printf("EnQueue failed\n");
ElemType elem;//存储出队元素
ret = DeQueue(Q, elem);
if (ret)printf("DeQueue %d Successfully\n", elem);
else printf("DeQueue failed\n");
return 0;
}