1. 掌握线性表的逻辑结构;
2. 链表的基本操作的实现;
3. 掌握利用C++/C编程语言实现数据结构的编程方法;
4. 通过上机时间加强利用数据结构解决实际应用问题的能力;
1. 实验前做好充分准备,包括复习线性表所学内容,事先预习好本次实验内容;
2. 实验时记录实验结果,按要求完成各题;
一、基础题:链表的实现
1. 编写链表基本操作函数:
l InitList(LinkList *L)初始化链表;(P49)
l InsertList(LinkList L, int item, int rc )向链表的指定位置插入元素;(P54)
l SeqInsertList(LinkList L, int item)向有序链表的插入元素,插入后链表仍有序;
l DeleteList(LinkList L, int item)删除指定元素值的链表记录;(P55)
l FindList(LinkList L, int item)查找链表中的元素;(P52)
l OutputList(LinkList L)输出链表中元素;
l FreeList(LinkList L)释放链表
2. 调用上述函数实现下列操作(验证)
l 初始化链表;
l 调用插入函数建立一个普通链表(InsertList1)和一个有序链表(InsertList2)
l 在链表中寻找指定的元素;
l 在链表中删除指定值的元素;
l 遍历并输出链表
注:每完成一个步骤,必须及时地输出链表元素,以便于观察操作结果。
LinkList.h
#include
#include
typedef int ElemType;
/**
单链表存储结构定义
**/
typedef struct Node
{
ElemType data;
struct Node *next;
}Node,*LinkList;
/*******初始功能
*初始时链表只有一个头结点
********/
void InitList(LinkList *L);
/*********插入功能******
* @参数 LinkList L: 链表头指针
* @参数 ElemType item:插入的数据值
* @参数 ElemType item:插入的位置
* @无返回值参数
***********************/
void InsertList(LinkList L,ElemType item,int rc);
/*********插入有序链表功能******
* @参数 LinkList L: 链表头指针
* @参数 ElemType item:插入的数据值
* 插入后链表仍有序
* @无返回值参数
***********************/
void SeqInsertList(LinkList L,ElemType item);
/*********删除功能******
* @参数 LinkList L:链表头指针
* @参数 ElemType item:删除结点的数据值
* @无返回值参数
***********************/
void DelList(LinkList L,ElemType item);
/*********查找功能******
* @参数 LinkList L:链表头指针
* @参数 ElemType item:查找的数据值
* @返回值:成功找到返回1否则返回0
***********************/
int FindList( LinkList L,ElemType item);
/*********输出功能******
* @参数 LinkList L:链表头指针
* @无返回值
***********************/
void OutputList(LinkList L);
/*********释放链表空间******
* @参数 LinkList L:链表头指针
* @无返回值
***********************/
void FreeList(LinkList L);
LinkList.cpp
#include "LinkList.h"
void InitList(LinkList *L)
{
*L = (LinkList)malloc(sizeof(Node));
(*L)->next=NULL;
}
void InsertList(LinkList L,ElemType item,int rc)
{
Node *pre,*s;
int k;
pre=L;
k=0; /*从"头"开始,查找第rc-1个结点*/
while(pre!=NULL&&knext;
k=k+1;
}
if(!pre) /*如当前位置pre为空表已找完还未数到第rc-1个,说明插入位置不合理*/
{
printf("插入位置不合理!");
return;
}
s=(Node*)malloc(sizeof(Node)); /*申请一个新的结点S */
s->data=item; /*值e置入s的数据域*/
s->next=pre->next; /*修改指针,完成插入操作*/
pre->next=s;
}
void SeqInsertList(LinkList L,ElemType item)
{
Node *pre, *r;
pre = L;
while (pre->next != NULL && pre->next->data - next;
}
r = (Node*)malloc(sizeof(Node));
r->data = item;
r->next = pre->next;
pre->next = r;
}
void DelList(LinkList L,ElemType item)
{
Node *pre,*r;
pre=L;
while(pre->next!=NULL && pre->next->data!=item) /*寻找元素值为item结点的前驱*/
{
pre=pre->next;
}
if(!(pre->next)) /* 没有找到合法的前驱位置,说明链表中不存在item值*/
{
printf("删除结点不合理!");
return;
}
r=pre->next;
pre->next=r->next; /*修改指针,删除结点r*/
free(r); /*释放被删除的结点所占的内存空间*/
printf("成功删除结点!\n");
}
int FindList( LinkList L,ElemType item)
{
Node *p;
p=L; /*从表中第一个结点开始 */
while (p!=NULL)
{
if (p->data!=item) /*若没找到,继续找下一结点*/
p=p->next;
else
break; /*找到结点值=item时退出循环 */
}
if (!p) return 0;
else return 1;
}
void OutputList(LinkList L)
{
Node *p;
p = L;
p = p->next;
while (p != NULL)
{
printf("%d ",p->data);
p = p->next;
}
printf("\n");
}
void FreeList(LinkList L)
{
Node *p,*r;
p = L;
while (p->next != NULL)
{
r = p->next;
p->next = r->next;
free(r);
}
/*释放所有结点,自行完成*/
}
main.cpp
#include "LinkList.h"
void main()
{
LinkList L;
InitList(&L); /*初始化,填空1*/;
ElemType item; /*某个线性表元素值*/
int rc; /*某个线性表元素的序号*/
int choice; /*输入选择*/
while(1)
{
printf( "\n请选择操作 1:指定位置追加 2: 升序追加 3: 查找结点\n" );
printf( " 4: 删除结点 5: 输出结点 6: 清空链表 0:退出\n" );
fflush( stdin ); /* 清空标准输入缓冲区 */
scanf( "%d", &choice );
switch( choice ) {
case 0: /* 退出 */
return;
case 1:
printf( "请输入新增结点键值和位置:" );
scanf( "%d%d", &item, &rc );
InsertList(L, item, rc);/*填空2,指定位置追加结点*/
break;
case 2:
printf( "请输入新增结点键值:" );
scanf( "%d", &item );
SeqInsertList(L,item);/*填空3,按升序追加结点*/
break;
case 3:
printf( "请输入要查找结点的键值:" );
scanf( "%d", &item );
rc=FindList(L, item);/*填空4,查找结点*/
if( rc > 0 )
printf( " 成功找到\n");
else
printf( " 没找到\n" );
break;
case 4:
printf( "请输入要删除结点的键值:" );
scanf( "%d", &item );
DelList(L, item);/*填空4,删除结点*/
break;
case 5:
printf( "\n链表内容为:\n" );
OutputList(L);/*填空5,输出结点*/
break;
case 6:
FreeList(L);/*填空6,清空链表*/
break;
}
}
}
二、提高题:链表的应用
1. 利用单链表实现多项式的乘法
【功能说明】利用单链表表示一元多项式,并完成两多项式的乘法运算。按指数的升序输入第一个一元多项式polya各项的指数和系数,且以输入0 0结束,构造第一个多项式单链表;按指数的升序输入第二个一元多项式polyb各项的指数和系数,构造第二个多项式单链表, 输出两一元多项式乘积的一元多项式polyc,并进行算法时间复杂度的分析。
例1:
【测试用例】
输入 |
0 2 1 3 4 -3 0 0 2 4 6 6 0 0 |
0 2 1 3 2 -3 0 0 1 1 2 4 0 0 |
输出 |
2 8 3 12 7 18 10 -18 |
1 2 2 11 3 9 4 -12 |
【设计要求】在给出的代码素材polymul.cpp文件中补充完整以下函数,实现多项式相乘的计算。
polymul.h
#include
#include
#include
using namespace std;
#define OK 1
#define ERROR 0
#define TRUE 1
#define FALSE 0
/*多项式结点结构定义*/
typedef struct Polynode
{
int coef; //系数
int exp; //指数
Polynode *next;
}Polynode, *Polylist;
/********输出功能
* @参数 Polylist poly: 多项式链表头指针
* @无返回值
*************/
void OutputPolylist(Polylist poly);
/********创建多项式链表
* @参数 Polylist poly: 多项式链表头指针
* @输入多项式各项的系数和指数,按指数升序构造链表,输入0 0结束
* @无返回值
****************/
void PolyCreate(Polylist poly);//按升序的方式输入多项式各项的系数和指数,输入0 0结束
/********插入功能
* @参数 Polylist poly: 多项式链表头指针
* @参数 int coef:系数
* @参数 int exp:指数
* @插入新的一项,按指数升序插入
* @无返回值
****************/
void PolyInsert(Polylist poly, int coef, int exp);//多项式中增加一项
/********多项式相加功能1
* @参数 Polylist polya: 多项式链表a的头指针
* @参数 Polylist polyb: 多项式链表b的头指针
* @多项式和由polya表示,多项式ployb释放
* @无返回值
****************/
void PolyAdd(Polylist polya, Polylist polyb); /*两个多项式相加,然后将和多项式存放在多项式polya中,并将多项式ployb删除*/
/********多项式相加功能2
* @参数 Polylist polya: 多项式链表a的头指针
* @参数 Polylist polyb: 多项式链表b的头指针
* @参数 Polylist polyc: 多项式链表c的头指针
* @多项式和由polyc表示
* @无返回值
****************/
void PolyAdd(const Polylist polya, const Polylist polyb,Polylist polyc);
/********多项式相乘功能
* @参数 Polylist polya: 多项式链表a的头指针
* @参数 Polylist polyb: 多项式链表b的头指针
* @参数 Polylist polyc: 多项式链表c的头指针
* @多项式乘积由polyc表示
* @无返回值
****************/
void PolyMul(Polylist polya,Polylist polyb,Polylist polyc);
polymul.cpp
#include "polymul.h"
void PolyInsert(Polylist poly, int coef, int exp)
{
Polynode *p = (Polynode *)poly;
bool flag = 0;
while (p->next != NULL) {
if (p->next->exp < exp) {
p = p->next;
}
else if (p->next->exp == exp) {
p->next->coef += coef;
flag = 1;
break;
}
else if (p->exp < exp && p->next->exp > exp) {
Polynode *s = new Polynode;
s->exp = exp, s->coef = coef;
s->next = p->next;
p->next = s;
flag = 1;
break;
}
}
if (!flag) {
Polynode *s = (Polynode *)new Polynode;
s->exp = exp, s->coef = coef;
s->next = p->next;
p->next = s;
}
}
void OutputPolylist(Polylist poly) //输出多项式
{
Polylist p = poly->next;
if (p!=NULL)
{
if (p->coef<0) cout<<"-";
cout<coef<<"x^"<exp<<" ";
p=p->next;
}
while (p != NULL)
{
if (p->coef > 0) cout << "+ ";
if (p->coef) cout << p->coef << "x^" << p->exp << " ";
p = p->next;
}
cout << endl;
return;
}
void PolyCreate(Polylist poly)
{
int c, e;
cin >> e >> c; /*键入多项式的指数和系数*/
while (c != 0) /*若c=0,则代表多项式的输入结束*/
{
PolyInsert(poly, c, e);
cin >> e >> c;
}
}
void PolyAdd(Polylist polya, Polylist polyb)
{
Polynode *p = polyb->next;
while (p != NULL)
{
PolyInsert(polya, p->coef, p->exp);//把polyb的第一项插入到polya中
polyb->next = p->next;// polyb多项式删除第1项
free(p);
p = polyb->next; //p指向polyb的新的第一个节点
}
free(polyb);//释放polyb的头结点
}
void PolyAdd(const Polylist polya, const Polylist polyb, Polylist polyc)
{
Polynode *p = polya->next;
while (p != NULL)
{
PolyInsert(polyc, p->coef, p->exp);
p = p->next;
}
p = polyb->next;
while (p != NULL)
{
PolyInsert(polyc, p->coef, p->exp);
p = p->next;
}
}
void PolyMul(Polylist polya, Polylist polyb, Polylist polyc)
{
Polynode *p = polya->next;
while (p != NULL) {
Polynode *pre = new Polynode;
pre = polyb->next;
while (pre != NULL) {
PolyInsert(polyc, p->coef * pre->coef, p->exp + pre->exp);
pre = pre->next;
}
delete pre;
p = p->next;
}
}
Main.cpp
#include "polymul.h"
int main()
{
Polylist polya, polyb, polyc;
Polynode *p;
int coef, exp;
cout << "请输入多项式A中各项指数和系数:(以0,0结束!)\n";
polya = (Polynode *)malloc(sizeof(Polynode));
polya->next = NULL;
PolyCreate(polya);
OutputPolylist(polya);
cout << "请输入多项式B中各项指数和系数:(以0,0结束!)\n";
polyb = (Polynode *)malloc(sizeof(Polynode));
polyb->next = NULL;
PolyCreate(polyb);
OutputPolylist(polyb);
polyc = (Polynode *)malloc(sizeof(Polynode));
polyc->next = NULL;
//PolyAdd(polya, polyb, polyc);
PolyMul(polya, polyb, polyc);
OutputPolylist(polyc);
return 0;
}
2. 利用循环单链表求解约瑟夫环问题
【问题描述】约瑟夫环问题:即n个人围成一个圆圈,然后从第一个人开始,按:1,2,3,……,m报数,数到m的人出圈,并有出圈者的下一个人重新开始报数,数到m又要出圈,如此类推,直到所有人都出圈,打印出圈的次序,其中n和m为输入数据。
【算法思想】
l 约瑟夫环满足线性表的逻辑结构,相邻两项具有前驱和后继的关系,故可以使用表结构表示。
l 通过尾插法创建不带头的单向循环链表(1,2,3……n);创建完毕后cur指针指向表尾;
l 计算出列人数number,初始值为0;
l 若出列人数不足n,则重复通过移动current指针到报数为m的前驱,删除current的后继并输出被删除结点的编号,number++;
#include
#include
#include
#include
/*结点类型定义
* @data:某结点的序号
* @next:指针域
* LinkList为结构指针类型
*/
typedef struct Node {
int data;
struct Node *next;
}Node, *link;
/*用循环链表求解约瑟夫环
* @参数link joseling:循环链表头指针
* @参数int n:总人数
* @参数int m:报数
* 无返回值
*/
void josephus(link joseling, int n, int m);
/*创建值为1~n的n个结点的不带头结点的循环单链表
* @参数int n:总人数
* 返回循环单链表的头指针
*/
link creatlink(int n);
/*打印循环链表
* @参数link head:循环单链表的头指针
*无返回值
*/
void printlink(link head);
/*移动,使p指针向前走i步
* @参数Node *p:指针p
* @参数int i:移动的次数
* 返回值指向结点的指针
*/
Node * move(Node *p, int i);
/*程序入口*/
int main()
{
int n, m, count, number;//count用于报数计数,number用于出列人数计数
link joselink, current, s;
printf("输入总人数n和报数规律m:\n");
scanf("%d %d", &n, &m);
joselink = creatlink(n);
printlink(joselink);
//不带头结点的循环单练表存储的约瑟夫环问题求解
josephus(joselink, n, m);
return 0;
}
link creatlink(int n)
{
Node *head = (Node *)malloc(sizeof(*head));
Node *cur;
head->data = 1;
cur = head;
for (int i = 2; i <= n; i++) {
cur->next = (Node *)malloc(sizeof(*cur->next));
cur = cur->next;
cur->data = i;
}
cur->next = head;
return head;
}
void josephus(link joselink, int n, int m)
{
Node *cur = joselink;
Node *del = NULL;
if (m == 1) {
while (cur->next != joselink) {
del = cur;
cur = cur->next;
printf("%d 被删除\n", del->data);
free(del);
}
printf("%d 被删除\n", cur->data);
free(cur);
return;
}
while (cur != del) {
cur = move(cur, m - 1);
del = cur->next;
printf("%d 被删除\n", del->data);
cur->next = del->next;
cur = del->next;
free(del);
}
}
Node *move(Node *p, int i)
{
if (i <= 0)
return p;
while (--i)
p = p->next;
return p;
}
void printlink(link head)
{
Node * current = head;
do {
printf("%d ", current->data);
current = current->next;
} while (current != head);
printf("\n");
return;
}
【测试结果】
【测试用例】采用下面的两组测试用例试试
输入 |
9 3 |
6 2 |
输出 |
3,6,9,4,8,5,2,7,1 |
2 4 6 3 1 5 |