考研初试算法题合集1线性表与链表
算法书上的代码都是伪代码,为了便于记忆,参考着资料实现了一遍,一切为了理解。
#include <iostream>
#include <stdio.h>
#include<stdlib.h>
#include<mm_malloc.h>
using namespace std;
typedef int Status;
#define ElemType int //此处将抽象数据类型定义为int
#define error 0//达不到目标要求则返回0
#define OK 1 //程序执行成功时返回1
#define LISTINCREAMENT 10//定义线性表扩容空间
#define OVERFLOW -2//宏定义溢出
typedef struct sqlist{
ElemType *elem;//定义了一个指向ElemType类型的指针elem
int listsize;//线性表最大表长
int length;//线性表实际长度
}Sqlist;
//顺序表插入
Status ListInsert_Sq(Sqlist &L,int i,ElemType x)
{
ElemType *newbase,*p,*q;
if(i<1||i>L.length+1) return error;
if(L.length>=L.listsize)//空间不足需要扩展
{
newbase=(ElemType*)realloc(L.elem,(L.listsize+LISTINCREAMENT)*sizeof(ElemType));
if(!newbase)exit(OVERFLOW);//申请不到内存,程序结束
L.elem=newbase;//成功申请内存,将线性表的首地址放到新申请到的内存上
L.listsize+=LISTINCREAMENT;//修改线性表的最大长度
}//if后为增强健壮性语句可不写
q=&(L.elem[i-1]);//q指针指向要插入的位置
for(p=&(L.elem[L.length-1]);p>=q;--p)
*(p+1)=*p;//从插入位置开始所有元素向后移动一位
*q=x;//插入待插入元素
L.length++;//线性表长度加一
return OK;
}
//顺序表删除
Status ListDelete_sq(Sqlist &L,int i,ElemType &e)
{
ElemType *p,*q;
if((i<1)||(i>L.length))return error;
p=&(L.elem[i]);
e=*p;
q=L.elem+L.length-1;
for(++p;p<=q;++p)
*(p-1)=*p;
--L.length;
}//ListDelete_sq
//顺序表合并
void MergeList_Sq(Sqlist La,Sqlist Lb,Sqlist &Lc)
//已知顺序线性表La和Lb的元素按值非递减排列
//归并La和Lb得到的新顺序表Lc,使Lc也按照非递减元素排列
{
ElemType *pa,*pb,*pc,*pa_last,*pb_last;
pa=La.elem;//指针pa指向线性表La的首地址
pb=Lb.elem;//指针pb指向线性表Lb的首地址
Lc.listsize=Lc.length=La.length+Lb.length;//Lc需要申请的内存空间,等于合并表Lc的长度,等于表La的长度与Lb的长度之和
pc=Lc.elem=(ElemType*)malloc(Lc.listsize*sizeof(ElemType));//为Lc申请内存空间,同时将指针pc指向Lc
if(!Lc.elem)exit(OVERFLOW);//无可用的内存空间时退出程序
pa_last=La.elem+La.length-1;//使指针Pa_last指向pa的最后一个元素
pb_last=Lb.elem+Lb.length-1;//使指针Pb_last指向pa的最后一个元素
while(pa<=pa_last&&pb<=pb_last)//便利条件为两个线性表都还没有便历完
{
if(*pa<*pb) //哪个表中的元素比较小先把哪个表中的元素插入
*pc++=*pa++;
else
*pc++=*pb++;
}
//由于两个表长度不一定相同,遍历后会剩一个未便历完表,将剩余表中的元素插入Lc
while(pa<=pa_last)*pc++=*pa++;
while(pb<=pb_last)*pc++=*pb++;
}//MergeList_Sq
//单链表结点结构
typedef struct Lnode{
ElemType data;
struct Lnode *next;
}Lnode,*LinkList;//此处定义指针类型的两种形式 使用Lnode定义时需要在被定义指针名称前加*,LinkList直接使用即可。
//单链表查找第i个元素
Status GetElem_L(LinkList L,int i,ElemType &e)
{
//L是带头节点的单链表的头指针
//第i个元素存在时将该元素值赋给e并返回OK,否则返回error
LinkList p;//Lnode *p;
p=L->next;int k=1; //初始化,p指向第一个节点,k为计数器
while(p&&k<i)//顺时针向后查找,直到p指向第i个元素或者p为空
{
p=p->next;
++k;
}
if(!p||k>i)//第i个元素不存在
return error;
e=p->data;
return OK;
}
//单链表的插入算法
Status ListInsert(LinkList &L,int i,ElemType e)
{
//在带头节点的单链表L中的第i的元素之前插入e
Lnode *p,*s;//p指针用来遍历,s指针用来插入赋值
p=L; int k=0;//初始化,p指向头节点,k为计数器
while(p&&k<i-1)//逐步移向p,直到P指向第i-1个元素或P为空
{
p=p->next;//
++k;
}
if(!p||k>i-1)
return error;//无法插入
if(!(s=(LinkList)malloc(sizeof(Lnode))));//申请元素e的结点空间
return OVERFLOW;//内存无空闲单元
s->data=e;
s->next=p->next;//插入元素e的结点
p->next=s;//
return OK;
}//ListInsert_L
//单链表的删除操作
Status ListDelete_L(LinkList &L,int i,ElemType &e)
{
//在带头结点的线性单链表L中,删除第i个元素,并由e返回其值
Lnode *p,*q;
p=L; int j=0;
while(p->next&&j<i-1)//p指针作为用来遍历的移动指针,最终指向第i-1个元素
{
p=p->next;
j++;
}
if(!(p->next)||j>i-1)//删除位置不合理
return error;
q=p->next;
p->next=q->next;
e=q->data;free(q);//删除并释放结点
return OK;
}
//表头插入法建立单链表(无头节点)
void Create_L(LinkList &L,int n)
{
Lnode *p;//此处用自由结点把输入的值一个一个插入链表中
L=(LinkList)malloc(sizeof(Lnode));
L->next=NULL;//始终保持第一个结点为空
for(int i=n;i>0;--i)
{
p=(LinkList)malloc(sizeof(Lnode));//初始化结点
scanf("%d",&p->data);
p->next=L->next;L->next=p;//从后向前插入结点
}
}
//表尾插入法建立不带头节点的链表
LinkList CreateL1()
{
LinkList h;
h = (LinkList)malloc(sizeof(Lnode));//初始化指针h始终指向第一个节点
LinkList p,r;//p为移动指针,r始终指向表尾,为表尾指针
r=h;//初始时表头即表尾
int n;//使用数字n来输入,也可先初始化一遍p结点,直接在while循环中输入p结点的值
while(scanf("%d",&n)!=EOF)
{
p=(Lnode*)malloc(sizeof(Lnode));//每次将移动结点初始化,以便进行下一次赋值
p->data=n;
r->next=p;
r=p;
}
r->next=NULL;//待所有节点插入完成后,将尾结点置空
return h;//返回表头指针所指地址
}
//有序单链表合并
void MergeList_L(LinkList &La,LinkList &Lb,LinkList &Lc)
{
Lnode *pa,*pb,*pc;//创立移动结点pa,pb,pc
pa=La->next;//pa指向La的第一个节点
pb=Lb->next;//pb指向Lb的第一个节点
while(pa&&pb){//遍历结束条件为pa与pb都不为空
if(pa->data<=pb->data){//哪个结点小先插入哪个节点
pc->next=pa;
pc=pa;
pa=pa->next;//插入一个结点后,相应链表的移动指针后移一位
}
else {
pc->next=pb;
pc=pb;
pb=pb->next;
}
}//while
pc->next=pa?pa:pb;//将最后剩的链表插入Lc中
free(Lb);
}//MergeList_L
//约瑟夫环
#include<iostream>
using namespace std;
const int N=20;
typedef struct node{//定义一个双向链表
int id;
struct node *next;//后继指针
struct node *pre;//前驱指针
}Node,*pNode;
pNode RingConstruct(int n)
{
int i;
pNode h,p,q;//h作为头指针,p作为尾指针,q作为指向输入元素的指针
h=(pNode)malloc(sizeof(Node));//初始化第一个结点
h->id=1;//给第一个结点编号
p=h;//初始时表头即表尾
for(i=2;i<=n;i++)
{
q=(pNode)malloc(sizeof(Node));//对每个要插入的结点进行初始化
q->id=i;//对每个插入结点编号
p->next=q;//表尾结点的的后继指针指向要插入的结点
q->pre=p;//要插入结点的前驱指针指向上一个结点
p=p->next;//表尾指针指向新插入的结点
}
p->next=h;
h->pre=p;//最后衔接表头表尾,完成循环链表
return h;
}
//boundMachine作为count函数的参数
int boundMachine(int order){//输入报数的次数序号,返回此次报数的上限
int boundList[4]={3,5,7,13};
return boundList[(order-1)%4];//返回每次的循环间隔,因为数组下标默认从0开始所以需要减1
}
//主函数中将boundMchine返回的参数传入count函数中的bound形参,即bound为每次循环间隔,first为链表首地址
pNode count(pNode first,int bound){
//返回当前趟起始结点,bound参数由boundMachine提供
pNode q;
q=first;//建立移动指针指向链表首地址
for(int i=2;i<=bound;i++){
q=q->next;
}//q最终指向经过一个以bound为循环间隔的循环到的结点,即要被删除的结点
return q;
}
//将currentNode从环中删除,并返回被删除的下一结点
pNode removeNode(pNode currentNode)
{
pNode first = currentNode->next;//当前删除结点的后继是下一趟的起始结点
currentNode->pre->next=first;
first->pre=currentNode->pre;
cout<<currentNode->id<<"";//删除currenNode并输出其值
free(currentNode);
return first;//返回删除结点的后继,也就是下一趟循环的起始结点
}
int main(){
pNode first,toRemove;//first为每一趟的起始结点,toRemove为要删除的结点,通过函数removeNode提供下一趟起始地址
int i;
first=RingConstruct(N);//构建一个含二十个元素的循环链表,将其初始链表首地址赋给first
for(int i=1;i<=N;i++){//循环遍历以每个i为起点,进行一次删除,有二十个人删除20次
toRemove=count(first, boundMachine(i));//通过count来计算每次要被删除的结点
first=removeNode(toRemove);//每次删除后都通过removeNode函数将下一趟第一个节点传入主函数
}
return 0;
}