问题及代码:
1、设计一个算法,将一个带头节点的数据域依次为a1,a2、、、an(n>=3)的单链表的所有节点逆置,及第一个节点的数据变为an,、、、,最后一个节点的数据变为a1。实现这个算法,并完成测试。
/*
*烟台大学计算机与控制工程学院
*作 者:杨宁
*完成日期:2015年10月3日
*问题描述:设计一个算法,将一个带头节点的数据域依次为a1,a2、、、an(n>=3)的单链表的所有节点逆置,
及第一个节点的数据变为an,、、、,最后一个节点的数据变为a1。实现这个算法,并完成测试。
*/
#include <stdio.h>
#include <malloc.h>
typedef int ElemType;
typedef struct LNode //定义单链表结点类型
{
ElemType data;
struct LNode *next; //指向后继结点
} LinkList;
void CreateListF(LinkList *&L,ElemType a[],int n);//头插法建立单链表
void CreateListR(LinkList *&L,ElemType a[],int n);//尾插法建立单链表
void DestroyList(LinkList *&L); //销毁单链表
void DispList(LinkList *L); //输出单链表
void InitList(LinkList *&L);//初始化单链表
bool ListEmpty(LinkList *L);//判断线性表是否为空表
int ListLength(LinkList *L);//求线性表的长度
bool GetElem(LinkList *L,int i,ElemType &e);//求线性表中某个数据的元素值
int LocateElem(LinkList *L,ElemType e);//按元素值查找
bool ListInsert(LinkList *&L,int i,ElemType e);//插入数据元素
bool ListDelete(LinkList *&L,int i,ElemType &e);//删除数据元素
void CreateListF(LinkList *&L,ElemType a[],int n)//头插法建立单链表
{
LinkList *s;
int i;
L=(LinkList *)malloc(sizeof(LinkList));
L->next=NULL;
for(i=0;i<n;i++)
{
s=(LinkList *)malloc(sizeof(LinkList));
s->data=a[i];
s->next=L->next;
L->next=s;
}
}
void CreateListR(LinkList *&L,ElemType a[],int n)//尾插法建立单链表
{
LinkList *s,*r;
int i;
L=(LinkList *)malloc(sizeof(LinkList));
r=L;
for(i=0;i<n;i++)
{
s=(LinkList *)malloc(sizeof(LinkList));
s->data=a[i];
r->next=s;
r=s;
}
r->next=NULL;
}
void InitList(LinkList *&L)//初始化单链表
{
L=(LinkList *)malloc(sizeof(LinkList)); //创建头结点
L->next=NULL;
}
void DestroyList(LinkList *&L)//销毁单链表
{
LinkList *pre=L,*p=L->next;
while(p!=NULL)
{
free(pre);
pre=p;
p=pre->next;
}
free(pre);
}
bool ListEmpty(LinkList *L)//判断线性表是否为空表
{
return(L->next==NULL);
}
int ListLength(LinkList *L)//求线性表的长度
{
int n=0;
LinkList *p=L;
while(p->next!=NULL)
{
n++;
p=p->next;
}
return(n);
}
void DispList(LinkList *L)//输出单链表
{
LinkList *p=L->next;
while(p!=NULL)
{
printf("%d ",p->data);
p=p->next;
}
printf("\n");
}
bool GetElem(LinkList *L,int i,ElemType &e)//求线性表中某个数据的元素值
{
int j=0;
LinkList *p=L;
while(j<i&&p!=NULL)
{
j++;
p=p->next;
}
if(p==NULL)
return false;
else
{
e=p->data;
return true;
}
}
int LocateElem(LinkList *L,ElemType e)//按元素值查找
{
LinkList *p=L->next;
int n=1;
while (p!=NULL && p->data!=e)
{
p=p->next;
n++;
}
if (p==NULL)
return(0);
else
return(n);
}
bool ListInsert(LinkList *&L,int i,ElemType e)//插入数据元素
{
int j=0;
LinkList *p=L,*s;
while (j<i-1 && p!=NULL) //查找第i-1个结点
{
j++;
p=p->next;
}
if (p==NULL) //未找到位序为i-1的结点
return false;
else //找到位序为i-1的结点*p
{
s=(LinkList *)malloc(sizeof(LinkList));//创建新结点*s
s->data=e;
s->next=p->next; //将*s插入到*p之后
p->next=s;
return true;
}
}
bool ListDelete(LinkList *&L,int i,ElemType &e)//删除数据元素
{
int j=0;
LinkList *p=L,*q;
while (j<i-1 && p!=NULL) //查找第i-1个结点
{
j++;
p=p->next;
}
if (p==NULL) //未找到位序为i-1的结点
return false;
else //找到位序为i-1的结点*p
{
q=p->next; //q指向要删除的结点
if (q==NULL)
return false; //若不存在第i个结点,返回false
e=q->data;
p->next=q->next; //从单链表中删除*q结点
free(q); //释放*q结点
return true;
}
}
#include <stdio.h>
#include <malloc.h>
#include "list.h"
void Reverse(LinkList *&L)
{
LinkList *p=L->next,*q;
L->next=NULL;
while (p!=NULL) //扫描所有的结点
{
q=p->next; //让q指向*p结点的下一个结点
p->next=L->next; //总是将*p结点作为第一个数据结点
L->next=p;
p=q; //让p指向下一个结点
}
}
int main()
{
LinkList *L;
ElemType a[]= {1,3,5,7, 2,4,8,10};
CreateListR(L,a,8);
printf("L:");
DispList(L);
Reverse(L);
printf("逆置后L: ");
DispList(L);
DestroyList(L);
return 0;
}
运行结果:
问题及代码:
2、已知L1和L2分别指向两个单链表的头结点,且已知其长度分别为m、n,请设计算法将L2连接到L1的后面。实现这个算法,完成测试,并分析这个算法的复杂度。
其中,头文件可用问题一中的头文件。
#include <stdio.h>
#include <malloc.h>
#include "list.h"
void Link(LinkList *&L1, LinkList *&L2)
{
LinkList *p = L1;
while(p->next != NULL) //找到L1的尾节点
p = p->next;
p->next = L2->next; //将L2的首个数据节点连接到L1的尾节点后
free(L2); //释放掉已经无用的L2的头节点
}
int main()
{
LinkList *A, *B;
int i;
ElemType a[]= {1,3,2,9};
ElemType b[]= {0,4,7,6,5,8};
InitList(A);
for(i=3; i>=0; i--)
ListInsert(A, 1, a[i]);
InitList(B);
for(i=5; i>=0; i--)
ListInsert(B, 1, b[i]);
Link(A, B);
printf("A:");
DispList(A);
DestroyList(A);
return 0;
}
运行结果:
问题及代码:
3、设计一个算法,判断单链表L是否是递增的。实现这个算法,并完成测试。
头文件用问题一的头文件
#include <stdio.h>
#include <malloc.h>
#include "list.h"
bool increase(LinkList *L)
{
LinkList *p = L->next, *q; //p指向第1个数据节点
if(p != NULL)
{
while(p->next != NULL)
{
q = p->next; //q是p的后继
if (q->data > p->data) //只要是递增的,就继续考察其后继
p = q;
else
return false; //只要有一个不是后继大于前驱,便不是递增
}
}
return true;
}
int main()
{
LinkList *A, *B;
int i;
ElemType a[]= {1, 3, 2, 9};
ElemType b[]= {0, 4, 5 ,6, 7, 8};
InitList(A);
for(i=3; i>=0; i--)
ListInsert(A, 1, a[i]);
InitList(B);
for(i=5; i>=0; i--)
ListInsert(B, 1, b[i]);
printf("A: %c\n", increase(A)?'Y':'N');
printf("B: %c\n", increase(B)?'Y':'N');
DestroyList(A);
DestroyList(B);
return 0;
}
运行结果:
知识点及总结:
以上提供了三种单链表的应用,分别是
1、将单链表的所有节点逆置。
2、将单链表1连接到单链表2后面。
3、判断单链表是否递增。
学习心得:
通过对这三种单链表应用的学习总结,更深刻体会了单链表。不理解的地方画画图就明白了许多。