链表(单链表,双链表)
将单链表和双链表写在了一块,就是一些简单的操作,还有序列合并,单链表逆序实现。
单链表
双链表(5.11 定义,初始化,5.14 插入删除,循环链表)
#include<bits/stdc++.h>
using namespace std;
//顺序表的定义
#define Maxsize 50
typedef int ElemType;//将线性表中的元素设置为整数。
typedef struct
{
ElemType *data;//动态顺序表
ElemType length;//顺序表当前长度
int size_list;
} SqList;
//单链表
typedef struct Node
{
ElemType data;//只是代表一个节点
struct Node *next;
} Node, *LinkList;
typedef struct DNode
{
//双链表定义
ElemType data;
struct DNode *prior,*next;
} DNode,*DLinklist;
//双链表初始化
void InitDLinkList(DLinklist &L)
{
L = (DLinklist)malloc(sizeof(DNode));
L->next = NULL;
L->prior = NULL;//前驱后继都设为NULL.
//return L;
}
//往双链表中插入,从头部开始,最先插入的会成为尾部
void Insert_DLink(DLinklist &L,ElemType e)
{
//刚开始的时候L为空啊,所有开始赋第一个值的时候不行!!!!
DNode *p = L;
DNode *s;
cout<<e<<endl;
s = (DNode*)malloc(sizeof(DNode));//给p分配空间
s->data = e;
if(p->next==NULL){//分两类插入,一类只有头节点,二是存在其他结点
s->prior = p;
p->next = s;
}
else{
s->next = p->next;
p->next->prior = s;
p->next = s;
s->prior = p;
}
}
int getDLinkList_length(DLinklist L)
{
DNode *p=L;
int len = 0;
while(p!=NULL){
len++;
p = p->next;
}
return len;
}
//删除双链表的第loc个节点
bool Delete_DLink(DLinklist &L, int loc)
{
//这里要先判断loc是否合法,如果loc不合法就不进行删除,但是要获取一共有多少节点
int len=getDLinkList_length(L);//这里一个地方调了很久,老是不能调用获取长度的函数,因为把他定义到删除节点后面了!!!
if(loc<1||loc>len)
return false;
else{
DNode *p;
p = L;
while(loc>0){
p=p->next;
loc--;//当前的p就是要删除的p
}
p->prior->next = p->next;
p->next->prior = p->prior;
free(p);
return true;
}
}
//打印双链表
void PrintDLink(DLinklist L)
{
DNode *p = L->next;
while(p)
{
cout<<p->data<<" ";
p = p->next;
}
}
//单链表初始化
void InitList_head(LinkList &L,int x)//按头插法
{
Node *s;
//int x;
L = (LinkList)malloc(sizeof(Node));//L为头结点
L->next=NULL;
s = (Node*)malloc(sizeof(Node));//给s节点内存
s->data = x;
s->next = NULL;
L->next = s;
}
int getlength(DLinklist L)//获取链表长度
{
DNode *p;
int length = 0;
p = L->next;
while(p)
{
length++;
p = p->next;
}
return length;
}
//在i上插入元素
bool Insert_list(LinkList &L,int loc,ElemType e)
{
Node *p = L->next;
Node *s;
// if(loc<1||loc>getlength(L))测试双链表的时候把getLength函数改了
// return false;
s = (Node*)malloc(sizeof(Node));
if(loc==1) //在第一个位置插入
{
s->data=e;
s->next=L->next;
L->next=s;
return true;
}
int j=1;//注意这里j的值
while(p&&j<loc-1) //将p节点移到要插入的地方
{
p = p->next;
j++;
}
s->next = p->next;
p->next = s;
s->data = e;
}
bool PrintLinkList(LinkList L)//打印单链表
{
if(L==NULL)
return false;
Node *p;
p=L->next;
while(p)
{
cout<<p->data<<" ";
p=p->next;
}
}
//单链表逆序函数
bool LinkReverse(LinkList &L)
{
//定义三个结点,逆序
Node *pre =NULL;//开始定义为空,以后为刚逆序的那个结点。
Node *now;
Node *next;
now = L->next;
// next = now->next;//初始
while(now!=NULL)
{
next = now->next;
now->next = pre;
pre = now;
now = next;//此时now会与next重合,下一个循环可以进行的话再将next=now->next
}
//此时初始结点应该为pre,因为now结点经过->next应该为空了。
L->next=pre;
}
int InitList_sq(SqList &L)
{
L.data = new ElemType[Maxsize];//分配空间
if(!L.data)
exit(-2);
L.size_list = Maxsize;//将容量设置为Maxsize
L.length = 0;
cout<<"Init!"<<endl;
return 0;
}
int ListInsert(SqList &L,int position,int e)
{
//插入函数
if(position<1||position>(L.length+1))
return -1;//判断插入的位置是否合法
if(L.length==L.size_list)
{
//链表满
return -1;
}
//在特定位置插入之后需要将后面的后移一位,而且要从最后一位开始
for(int i=L.length; i>=position; i--)
{
L.data[i] = L.data[i-1];//注意position和实际下标存在1的差距
}
L.data[position-1] = e;
L.length++;//当前长度加一
return 0;
}
int ListSearch(SqList L,ElemType e)
{
//查找元素e在第几个
for(int i=0; i<L.length; i++)
{
if(L.data[i]==e)
return i+1;
}
return -1;//找不到
}
int ListDel(SqList &L,int position,ElemType &e)
{
if(position<1||position>L.length)
return false;
//删除某个位置上的元素,返回删除的元素
//删除这个位置上的。后面的依次向前位移,
e = L.data[position-1];
for(int i = position; i<L.length; i++)
{
L.data[i-1] = L.data[i];
}
L.length--;
}
void PrintList(SqList L)
{
for(int i=0; i<L.length; i++)
{
cout<<L.data[i]<<" ";
}
cout<<endl;
}
//将两个有序表合并为一个有序表
void Merge(SqList a,SqList b,SqList &c)
{
//将a,b合并为c,并带回
int i,j,k;
i=0,j=0,k=1;
while(i<a.length&&j<b.length)
{
if(a.data[i]<=b.data[j])
{
//a的表头不大于b的表头
c.data[k]=a.data[i];
i++;
k++;
}
else
{
c.data[k]=b.data[j];
k++;
j++;
}
}
if(i==a.length&&j<b.length)
{
for(; j<b.length; j++)
{
c.data[k]=b.data[j];
k++;
}
}
if(i<a.length&&j==b.length)
{
for(; i<a.length; i++)
{
c.data[k]=a.data[i];
k++;
}
}
c.length=k;//不要忘了最后给length赋值,否则就为0;
}
int main()
{
/*
测试:关于合并两个有序列表
SqList a,b,c;
InitList_sq(a);//初始化
InitList_sq(b);
InitList_sq(c);
for(int i=0;i<4;i++){
ListInsert(a,i+1,i+1);
}
for(int j=0;j<5;j++){
ListInsert(b,j+1,j+4);
}
PrintList(a);
PrintList(b);
Merge(a,b,c);
PrintList(c);
//测试:单链表
LinkList L;
InitList_head(L,1);
Insert_list(L,1,2);
Insert_list(L,1,3);
Insert_list(L,1,4);
Insert_list(L,1,5);//头初始化,在i处插入一个值。此时单链表的值为5 4 3 2 1
PrintLinkList(L);
cout<<endl;
//单链表逆序
LinkReverse(L);
PrintLinkList(L);
*/
DLinklist L;
InitDLinkList(L);
Insert_DLink(L,1);
Insert_DLink(L,2);
Insert_DLink(L,3);
Insert_DLink(L,4);
PrintDLink(L);
Delete_DLink(L,3);
cout<<"删除后的"<<endl;
//int len = getDLinkList_length(L);
//cout<<len;
PrintDLink(L);//删除成功
}
栈和队列
顺序栈(5.17)
#include <iostream>
using namespace std;
#define MaxSize 50
typedef int Elemtype;
//栈和队列的基本操作
//顺序栈的声明
typedef struct{
Elemtype data[MaxSize];
int top;
}Sqstack;
void Init_stack(Sqstack &S)
{
S.top=-1;//栈顶为-1时,栈为空
}
//判断栈是否为空
bool EmptyStack(Sqstack S)
{
if(S.top==-1)
return true;//空
else return false;//不空
}
//push入栈
bool Push_stack(Sqstack &s,Elemtype e)
{
if(s.top==MaxSize-1){
//栈满,无法push
return false;
}
s.data[++s.top]=e;//先++,比如开始的时候top为-1push的时候要在0的位置放元素,所以先++ 为0后再赋值。
return true;
}
//出栈
bool Pop_Stack(Sqstack &s,Elemtype &x){
//还是先判空
if(!EmptyStack(s)){
x= s.data[s.top--];//不要忘了减一
return true;
}
return false;
}
int main()
{
//顺序栈测试
Sqstack s;
Init_stack(s);
Push_stack(s,1);
Push_stack(s,2);
Push_stack(s,3);
Push_stack(s,4);
int x;
Pop_Stack(s,x);
cout<<x<<endl;
Pop_Stack(s,x);
cout<<x<<endl;
Pop_Stack(s,x);
cout<<x<<endl;
}
队列(循环顺序队列5.18)
#include <iostream>
using namespace std;
#define MaxSize 4
typedef int Elemtype;
//栈和队列的基本操作
//顺序栈的声明
typedef struct{
Elemtype data[MaxSize];
int top;
}Sqstack;
//循环顺序队列的定义
typedef struct {
Elemtype data[MaxSize];
int frt,rear;
int len;//用来记录队列长度
}SqQueue;
void Init_Queue(SqQueue &q)
{
q.frt = q.rear = 0;
q.len = 0;
}
//入队操作
bool EnQueue(SqQueue &q,Elemtype e)
{
//先判断队满
if(q.frt==q.rear&&q.len==MaxSize){
return false;
}
q.data[q.rear]=e;//只能从队尾插入
q.rear = (q.rear+1)%MaxSize;//循环
q.len++;
return true;
}
//出队操作,只从对头出队
bool DeQueue(SqQueue &q,Elemtype &e)
{
//判断队列是否为空
if(q.frt==q.rear&&q.len==0)return false;
e=q.data[q.frt];
q.frt = (q.frt+1)%MaxSize;
q.len--;
return true;
}
//打印输出队列里的元素
bool Print_Q(SqQueue q)
{
if(q.frt==q.rear&&q.len==0)return false;
for(int i=0;i<q.len;i++){
int x = (q.frt+i)%MaxSize;
cout<<q.data[x]<<" ";
}
}
typedef struct Linknode{
Elemtype data;
struct Linknode *next;
}*LiStack;
void Init_stack(Sqstack &S)
{
S.top=-1;//栈顶为-1时,栈为空
}
//判断栈是否为空
bool EmptyStack(Sqstack S)
{
if(S.top==-1)
return true;//空
else return false;//不空
}
//push入栈
bool Push_stack(Sqstack &s,Elemtype e)
{
if(s.top==MaxSize-1){
//栈满,无法push
return false;
}
s.data[++s.top]=e;//先++,比如开始的时候top为-1push的时候要在0的位置放元素,所以先++ 为0后再赋值。
return true;
}
//出栈
bool Pop_Stack(Sqstack &s,Elemtype &x){
//还是先判空
if(!EmptyStack(s)){
x= s.data[s.top--];//不要忘了减一
return true;
}
return false;
}
int main()
{
/*
//顺序栈测试
Sqstack s;
Init_stack(s);
Push_stack(s,1);
Push_stack(s,2);
Push_stack(s,3);
Push_stack(s,4);
int x;
Pop_Stack(s,x);
cout<<x<<endl;
Pop_Stack(s,x);
cout<<x<<endl;
Pop_Stack(s,x);
cout<<x<<endl;
*/
//队列测试
SqQueue q;
Init_Queue(q);
EnQueue(q,1);
EnQueue(q,2);
EnQueue(q,3);
EnQueue(q,4);
EnQueue(q,5);
Print_Q(q);
cout<<endl;
int x;
DeQueue(q,x);
cout<<x<<endl;
Print_Q(q);
cout<<endl;
DeQueue(q,x);
cout<<x<<endl;
Print_Q(q);
cout<<endl;
EnQueue(q,5);
Print_Q(q);
}
栈的应用
- 匹配括号
#include<bits/stdc++.h>
using namespace std;
#define MaxSize 50
//后缀表达式求值和括号匹配,使用栈
typedef struct{
int top;
char data[MaxSize];
int Size;
}Stack;
//入栈,出栈操作
bool Push(Stack &s,char a)
{
if(s.Size>MaxSize){
cout<<"栈满了!";
return false;
}
s.data[++s.top]=a;
s.Size++;
return true;
}
bool Pop(Stack &s,char &a)
{
if(s.top==-1)
{
cout<<"Kong的栈";
return false;
}
a=s.data[s.top--];
s.Size--;
}
//括号匹配
int main()
{
Stack s;
s.top=-1;//初始化
s.Size=0;
char str[13];
cin>>str;
int len = strlen(str);
//cout<<len;
for(int i=0;i<len;i++){
if(str[i]=='('||str[i]=='['||str[i]=='{')
Push(s,str[i]);
else {
char p;
Pop(s,p);
if(str[i]==')'&&p=='(')
continue;
else if(str[i]==']'&&p=='[')
continue;
else if(str[i]=='}'&&p=='{')
continue;
else{
cout<<"格式错误";
return 0;
}
}
}
if(s.Size!=0){
cout<<"格式错误";
}
cout<<"格式正确";
}
- 后缀表达式求值(用的链栈,没有顺序栈)
#include<bits/stdc++.h>
using namespace std;
#define MaxSize 50
//后缀表达式求值
//从左到右遍历字符串,遇到数字入栈,遇到运算符,取出栈中两个元素进行运算,将结果入栈。这次使用链栈
typedef struct LNode{
int data;
LNode *next;
} LNode,*LinkNode;
//判断栈是否为空
bool Empty(LinkNode s)
{
if(s->next==NULL)
return true;
else return false;
}
//入栈操作
void L_push(LinkNode &s,int e)
{
LNode *p;
p=(LNode*)malloc(sizeof(LNode));
p->data = e;
p->next=s->next;
s->next=p;
}
//出栈操作
void L_Pop(LinkNode &s,int &e)//需要带回出栈的元素
{
if(!Empty(s)){
//
LNode *p;
p = s->next;//p为栈顶的那一个元素
e = p->data;
s->next = p->next;//断开p
free(p);
}
}
int main()
{
//后缀表达式求值
char str[20];
cin>>str;
//cout<<str;
LinkNode s;
s=(LNode*)malloc(sizeof(LNode));//如果这里不分配空间有的程序会报错。
s->next=NULL;//初始化
int len = strlen(str);
for(int i=0;i<len;i++){
if(str[i]>=48&&str[i]<=57){
//该字符为数字
int e= str[i]-48;
// cout<<e;
L_push(s,e);
}
else{
int result;
int right;
L_Pop(s,right);
int left;
L_Pop(s,left);
if(str[i]=='+')
result = right+left;
else if(str[i]=='-')
result = left-right;
else if(str[i]=='*')
result = left*right;
else if(str[i]=='/')
result = left/right;
L_push(s,result);
}
}
//如果后缀表达式正确的话,此时栈中应该就剩一个结果
if(s->next->next!=NULL){
cout<<"表达式错误"<<endl;
}
else cout<<"结果为:"<<s->next->data;
}
- 中缀转后缀(不涉及括号)
包含对小括号的处理:从左到右遍历中缀表达式的每个数字和符号,若是数字就输出,即成为后缀表达式的一部分;若是符号,则判断其与栈顶符号的优先级,是右括号或优先级低于栈顶符号(乘除优先加减)则栈顶元素依次出找并输出,并将当前符号进栈,注意舍弃左括号再入栈当前符号。一直到最终输出后缀表达式为止。
#include<bits/stdc++.h>
using namespace std;
#define MaxSize 50
typedef struct LNode
{
char data;
LNode *next;
} LNode,*LinkNode;
//判断栈是否为空
bool Empty(LinkNode s)
{
if(s->next==NULL)
return true;
else
return false;
}
//入栈操作
void L_push(LinkNode &s,char e)
{
LNode *p;
p=(LNode*)malloc(sizeof(LNode));
p->data = e;
p->next=s->next;
s->next=p;
}
//出栈操作
void L_Pop(LinkNode &s,char &e)//需要带回出栈的元素
{
if(!Empty(s))
{
//
LNode *p;
p = s->next;//p为栈顶的那一个元素
e = p->data;
s->next = p->next;//断开p
free(p);
}
}
int main()
{
//中缀表达式转后缀表达式,因为计算机本身做运算也有这个过程
//思路:从左到右扫描式子,遇到数字直接输出,遇到运算符,如果栈空就入栈
//如果栈中有运算符,则比较优先级,如果栈中的优先级高或者相等就输出,如果栈中优先级低就入栈当前运算符.
LinkNode s;
s=(LNode*)malloc(sizeof(LNode));//如果这里不分配空间有的程序会报错。
s->next=NULL;//初始化
char str[20];
cin>>str;
int len = strlen(str);
for(int i=0; i<len; i++)
{
if(str[i]>=48&&str[i]<=57)
{
//该字符为数字
cout<<str[i];
}
else
{
if(Empty(s))
{
//栈为空,则入栈运算符
L_push(s,str[i]);
}
else
{
//栈不空,比较优先级
if(str[i]=='*'||str[i]=='/')
{
if(s->next->data=='/'||s->next->data=='*') //栈中优先级相同
{
while(s->next->data=='*'||s->next->data=='/')
{
char c;
L_Pop(s,c);
cout<<c;
}
L_push(s,str[i]);//当前入栈
}
L_push(s,str[i]);//当前入栈
}
else
{
while(!Empty(s)) //如果遍历到+-,则栈中的肯定都能输出
{
char c;
L_Pop(s,c);
cout<<c;
}
L_push(s,str[i]);//当前入栈
}
}
}
}
while(!Empty(s)) //最后输出栈中的运算符
{
char c;
L_Pop(s,c);
cout<<c;
}
}