本次主要介绍循环链表、队列、栈和堆
1、已知n个人(以编号1,2,3,...,n分别表示)围坐在一张圆桌周围,从编号为k的人开始报数,数到m的那个人出列,他的下一个人又从k开始报数,数到m的那个人出列,依次重复下去,直到圆桌的人全部出列。试用C++编写实现。
解析:本题就是约瑟夫环问题的实际场景,要通过输入n、m、k三个正整数,求出列的序列。这个问题采用的是典型的循环链表的数据结构,就是将一个链表的尾元素指针指向队首元素:
p->link=head;
解决问题的核心步骤如下:
(1)建立一个具有n个链节点、无头节点的循环链表。
(2)确定第一个报数人的位置。
(3)不断的从链表中删除链节点,直到链表为空。
答案:
12345678910111213141516171819202122232425262728293031323334353637383940#include<iostream>
using
namespace
std;
typedef
struct
LNode
{
int
data;
struct
LNode *link;
}LNode,*LinkList;
//n为总人数,k为第一个开始报数的人,m为出列者喊到的数
void
JOSEPHUS(
int
n,
int
k,
int
m)
{
//p为当前节点,r为辅助节点,指向p的前驱节点,list为头节点
LinkList p,r,list,curr;
//简历循环链表
p=(LinkList)
malloc
(
sizeof
(LNode));
p->data=1;
p->link=p;
curr=p;
for
(
int
i=2;i<=n;i++)
{
LinkList t=(LinkList)
malloc
(
sizeof
(LNode));
t->data=i;
t->link=curr->link;
curr->link=t;
curr=t;
}
//把当前指针移动到第一个报数的人
r=curr;
while
(k--)
r=p,p=p->link;
while
(n--)
{
for
(
int
s=m-1;s--;r=p,p=p->link);
r->link=p->link;
printf
(
"%d->"
,p->data);
free
(p);
p=r->link;
}
}
2、编程实现队列的入队/出队操作。
答案:
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556#include<iostream>
using
namespace
std;
typedef
struct
student
{
int
data;
struct
student *next;
}node;
typedef
struct
linkqueue
{
node *first,*rear;
}queue;
//队列的入队
queue *insert(queue *HQ,
int
x)
{
node *s;
s=(node *)
malloc
(
sizeof
(node));
s->data=x;
s->next=NULL;
if
(HQ->rear==NULL)
{
HQ->first=s;
HQ->rear=s;
}
else
{
HQ->rear->next=s;
HQ->rear=s;
}
return
(HQ);
}
//队列的出队
queue *
remove
(queue *HQ)
{
node *p;
if
(HQ->first==NULL)
printf
(
"\n yichu"
);
else
{
p=HQ->first;
if
(HQ->first==HQ->rear)
{
HQ->first=NULL;
HQ->rear=NULL;
}
else
{
HQ->first=HQ->first->next;
free
(p);
}
return
(HQ);
}
}
3、用两个栈实现一个队列的功能,请用C++实现。
解析:思路如下:
假设两个栈A和B,且都为空。
可以认为栈A提供入队列的功能,栈B提供出队列的功能。
入队列:入栈A。
出队列:
(1)如果栈B不为空,直接弹出栈B的数据。
(2)如果栈B为空,则依次弹出栈A的数据,放入栈B中,再弹出栈B的数据。
答案:
12345678910111213141516171819202122232425262728293031323334353637383940414243#include<iostream>
#include<stack>
using
namespace
std;
template
<
class
T>
struct
Queue
{
void
push(T &t)
{
s1.push(t);
}
T front()
{
if
(s2.empty())
{
if
(s1.size()==0)
throw
;
while
(!s1.empty())
{
s2.push(s1.top());
s1.pop();
}
}
return
s2.top();
}
void
pop()
{
if
(s2.empty())
{
while
(!s1.empty())
{
s2.push(s1.top());
s1.pop();
}
}
if
(!s2.empty())
s2.pop();
}
stack<T> s1;
stack<T> s2;
}
4、请讲诉heap和stack的差别。
解析:在进行C/C++编程时,需要程序员对内存的了解比较精准。经常需要操作的内存可分为以下几个类别:
(1)栈区(stack):由编译器自动分配和释放,存放函数的参数值、局部变量的值等。其操作方式类似于数据结构中的栈。
(2)堆区(heap):一般由程序员分配和释放,若程序员不释放,程序结束时可能由操作系统回收。注意它与数据结构中的堆是两回事,分配方式倒是类似于链表
(3)全局区(静态区)(static):全局变量和静态变量的存储是放在一块的,初始化的全局变量和静态变量在一块区域,未初始化的全局变量和静态变量在相邻的另一块区域。程序结束后由系统释放。
(4)文字常量区:常量字符串就是放在这里的,程序结束后由系统释放。
(5)程序代码区:存放函数体的二进制代码。
答案:
(1)stack的空间由操作系统自动分配/释放,heap上的空间手动分配/释放。
(2)stack空间有限,heap是很大的自由存储区。
(3)C中的malloc函数分配内存空间即在堆上,C++中对应的是new操作符。
(4)程序在编译期对变量和函数分配内存都在栈上进行,且程序运行过程中函数调用时参数的传递也在栈上进行。