第二章 栈、队列、链表
完整代码下载
第一节 队列
首先,引入两个整形变量 head 和 tail 分别记录队列的队首和队尾的下一位(为当队列中只剩下一个元素时,队首和队尾重合会带来一些麻烦)。
在队首加一个数: head++
在队尾增加一个数: q[tail]=x;tail++
队列 : 队列是一种特殊的线性结构,它只允许在队列的首部(head)进行删除操作,这称为“出队”,而在队列的尾部(tail)进行插入操作,这称为“入队”。当队列中没有元素时(即 head==tail),称为空队列。我们称为“先进先出”(First In First Out,FIFO)原则。
我们可以将队列的三个基本元素(一个数组,两个变量)封装为一个结构体类型
struct queue
{
int data[100];//队列的主体,用来存储内容
int head;//队首
int tail;//队尾
};
那么我们如何定义结构体变量和访问结构体变量的内部成员呢?
struct queue q;
q.head=1;
q.tail=1;
scanf("%d",&q.data[q.tail]);
接下来我们去解决一个问题:一串加密过的9个数字,首先将第 1个数删除,紧接着将第 2个数放到这串数的末尾,再将第 3个数删除并将第 4个数放到这串数的末尾,再将第 5个数删除……直到剩下后一个数,将后一个数也删除。最后按照刚才删除的顺序,把这些删除的数连在一起。
//算法06
struct queue q;
int i;
q.head=1;
q.tail=1;
for(i=1;i<=9;i++)
{
scanf("%d",&q.data[q.tail]);
q.tail++;
}
while(q.head<q.tail)
{
printf("%d",q.data[q.head]);
q.head++;
q.data[q.tail]=q.data[q.head];
q.tail++;
q.head++;
}
第二节 栈
队列结构为先进先出,而栈结构为后进后出。所以栈的实现很简单,只需要一个一维数组和一个指向栈顶的变量 top就可以了。
接下来我们用栈结构来判断一个字符串是否为回文字符串。
回文字符串: 指正读反读均相同的字符序列。
入栈操作: top++;s[top]=x;
或者简写为 s[++top]=x;
//算法07
char a[101],s[101];
int i,len,mid,next,top;
gets(a);//读入一行字符串
len=strlen(a);//求字符串长度
mid=len/2-1;//求字符串的中点
top=0;//栈的初始化
for(i=0;i<=mid;i++) //将mid前的字符依次入栈
s[++top]=a[i];
//判断字符串的长度是奇数还是偶数,并找出需要进行字符匹配的起始下标
if(len%2==0)
next=mid+1;
else
next=mid+2;
//开始匹配
for(i=next;i<=len-1;i++)
{
if(a[i]!=s[top])
break;
top--;
}
//如果top的值为0,则说明栈内所有的字符都被一一匹配了
if(top==0)
printf("YES");
else
printf("NO");
第三节 链表
有一串已经从小到大排好序的数 2 3 5 8 9 10 18 26 32。现需要往这串数中插入 6使其得到的新序列仍符合从小到大排列
如果使用数组的话会耽误很多时间:
但是如果使用链表的话就会简单很多:
每一个结点都由两个部分组成。左边的部分用来存放具体的数值,那么用一个整型变量就可以;右边的部分需要存储下一个结点的地址,可以用指针来实现(也称为后继指针) 。
我们定义一个结构体类型来存储这个结点:
struct node
{
int data;
struct node *next;
};
建立链表
首先我们需要一个头指针 head 指向链表的开始。
struct node *head;
head = NULL;//头指针初始为空
创建第一个结点,并用临时指针 p指向这个结点。
struct node *p;
//动态申请一个空间,用来存放一个结点,并用临时指针p指向这个结点
p=(struct node *)malloc(sizeof(struct node));
分别设置新创建的这个结点的左半部分和右半部分。
scanf("%d",&a);
p->data=a;//将数据存储到当前结点的data域中
p->next=NULL;//设置当前结点的后继指针指向空,也就是当前结点的下一个结点为空
-> 叫做结构体指针运算符,也是用来访问结构体内部成员的。因为此处 p 是一个指针,所以不能使用.号访问内部成员。
设置头指针并设置新创建结点的*next 指向空。
if(head==NULL)
head=p;//如果这是第一个创建的结点,则将头指针指向这个结点
else
q->next=p;//如果不是第一个创建的结点,则将上一个结点的后继指针指向当前结点
后要将指针 q也指向当前结点。
q=p;//指针q也指向当前结点
接下来需要往链表中插入 6
首先用一个临时指针 t从链表的头部开始遍历。
t=head;//从链表头部开始遍历
等到指针 t的下一个结点的值比 6大的时候,将 6插入到中间。
scanf("%d",&a);//读入待插入的数
while(t!=NULL)//当没有到达链表尾部的时候循环
{
if(t->next->data > a)//如果当前结点下一个结点的值大于待插入数,将数插入到中间
{
p=(struct node *)malloc(sizeof(struct node));//动态申请一个空间,用来 存放新增结点
p->data=a;
p->next=t->next;//新增结点的后继指针指向当前结点的后继指针所指向的结点
t->next=p;//当前结点的后继指针指向新增结点
break;//插入完毕退出循环
}
t=t->next;//继续下一个结点
}
完整代码
//算法08