链表实现奇偶数分类
一、需求分析
1、数据存储结构为链表
2、输入形式为键盘包括数字1-9、空格、和回车
3、输出形式为打印形式
4、包含链表的基本操作
5、能够完成指定要求的排序操作
6、能够从一个链表中分离出奇数和偶数
7、能够删除非指定数字
二、概要设计
一、抽象数据类型定义
ADT numbers{
数据对象:{}
数据关系:{<a,b>}
基本操作:
MakeNode(Link &p, ElemType e)
操作结果:分配由p指向的值为e的结点
FreeNode(Link &p)
操作结果:释放p所指的结点
InitList(LinkList &L)
操作结果:初始化一个链表L
ClearList(LinkList &L)
初始条件:链表存在
操作结果:链表L重置为空表,并释放原链表的结点空间
DestroyList(LinkList &L)
初始条件:链表L存在
操作结果:销毁链表L,L不再存在
InsFirst(LinkList &L,Link s)
初始条件:链表L存在
操作结果:将s所指结点插入在第一个结点之前
GetCurElem(Link p)
操作结果:返回p所指结点中数据元素的值
Compare(Link p1, Link p2)
操作结果:如果p1所指元素大于p2则返回TURE,否则返回FALSE
ExchangeData(Link &p1,Link &p2)
操作结果:交换两个结点的数据
sort(LinkList &L)
操作结果:将链表排序为非递增链表
DeleteNode(LinkList &L, Link s)
初始条件:链表L不为空
操作结果:删除s所指结点
PrintList(LinkList &L)
初始条件:链表L存在
操作结果:在屏幕上打印出链表中的元素
}
二、宏定义部分
#include<stdio.h>
#include<stdlib.h>
#define TRUE 1
#define FALSE 0
#define OK 1
#define ERROR 0
三、主程序流程图
四、程序结构图
三、详细设计
一、数据类型设计
/*顺序表的定义/
typedef struct LNode{ // 结点类型
ElemType data; //数据域
struct LNode *next; //指针域
} *Link, *Position;
typedef struct { // 链表类型
Link head; // 头结点
Link tail; // 最后一个结点
int len; // 线性链表中的数据元素格式
} LinkList;
二、数据操作
Status MakeNode(Link &p, ElemType e){
// 分配由p指向的值为e的结点。若分配失败,则返回ERROR
p = (Link)malloc(sizeof(LNode));
if(!p){
return ERROR;
}
p->data = e;
}
void FreeNode(Link &p){
// 释放p所指结点
free§;
p = NULL;
}
Status InitList(LinkList &L){
// 构造一个空的线性链表L
Link p;
p = (Link)malloc(sizeof(LNode)); // 生成头结点
if§{
p->next = NULL;
L.head = L.tail = p;
L.len = 0;
}
else
return ERROR;
}
void ClearList(LinkList &L){ // 将线性链表L重置为空表,并释放原链表的结点空间
Link p,q;
if(L.head!=L.tail) // 不是空表
{
p=q=L.head->next;
L.head->next=NULL;
while(p!=L.tail)
{
p=q->next;
free(q);
q=p;
}
free(q);
L.tail=L.head;
L.len=0;
}
}
Status DestroyList(LinkList &L){ // 销毁线性链表L,L不再存在(见图2.44)
ClearList(L); // 清空链表
FreeNode(L.head);
L.tail=NULL;
L.len=0;
}
Status InsFirst(LinkList &L,Link s){ // 形参增加L,因为需修改L
// h指向L的一个结点,把h当做头结点,将s所指结点插入在第一个结点之前
Link h = L.head;
s->next=h->next;
h->next=s;
if(h==L.tail) // h指向尾结点
L.tail=h->next; // 修改尾指针
L.len++;
}
Status Compare(Link p1, Link p2) {
if(p1->data > p2->data){
return TRUE;
}else{
return FALSE;
}
}
void ExchangeData(Link &p1,Link &p2){ // 已知p指向线性链表中的一个结点,用e更新p所指结点中数据元素的值
ElemType temp = p1->data;
p1->data = p2->data;
p2->data = temp;
}
ElemType GetCurElem(Link p){ // 已知p指向线性链表中的一个结点,返回p所指结点中数据元素的值
return p->data;
}
void sort(LinkList &L){
for (int i = 0; i < L.len; i++)
{
Link p2 = L.head->next;
if(p2->next==NULL){
return;
}
Link p1 = L.head->next->next;
for (int j = 0; j <= L.len-2; j++)
{
if(Compare(p1,p2)){
ExchangeData(p1, p2);
}
p1 = p1->next;
p2 = p2->next;
}
}
}
Status DeleteNode(LinkList &L, Link s){
if(s == L.head || L.head == L.tail){
return FALSE;
}
if(s == L.tail){
Link p = L.head;
while(p->next!=L.tail){
p = p->next;
}
p->next = NULL;
L.tail = p;
FreeNode(s);
L.len–;
return TRUE;
}
Link p = L.head;
while(p->next!=s){
p = p->next;
}
p->next = p->next->next;
FreeNode(s);
L.len–;
return TRUE;
}
void PrintList(LinkList &L){
Link p = L.head->next;
for (int i = 0; i < L.len; i++)
{
printf("%d ", p->data);
p = p->next;
}
}
三、运算功能
void Function_1(LinkList &L, int mink, int maxk){//筛选出指定范围的数据
Link p1 = L.head;
while (p1->next!=NULL)
{
Link p2 = p1;
p1 = p1->next;
if(p1->data<mink || p1->data>maxk){
DeleteNode(L, p1);
p1 = p2;
}
}
}
void Function_2(LinkList &L_A, LinkList &L_B, LinkList &L_C){//分离出奇偶数
Link p = L_A.head;
while (p->next!=NULL)
{
p = p->next;
if (p->data%2==1)
{
Link s;
MakeNode(s, p->data);
InsFirst(L_B, s);
}
else
{
Link s;
MakeNode(s, p->data);
InsFirst(L_C, s);
}
}
}
四、主程序
int main(){
LinkList L_A, L_B, L_C;
InitList(L_A);
InitList(L_B);
InitList(L_C);
char a;
int b;
scanf("%d", &b);
scanf("%c", &a);
while (a!='\n')
{
Link p;
MakeNode(p, b);
InsFirst(L_A, p);
scanf("%d", &b);
scanf("%c", &a);
}
Link p;
MakeNode(p, b);
InsFirst(L_A, p);
sort(L_A);
Function_1(L_A, 0, 20);
Function_2(L_A, L_B, L_C);
sort(L_B);
sort(L_C);
printf("\nL_A:");
PrintList(L_A);
printf("\nL_B:");
PrintList(L_B);
printf("\nL_C:");
PrintList(L_C);
}
四、调试分析
一、主要问题与解决方案
1、发现排序出现问题,调试后发现是遍历链表时循环一遍结束后未让指针指向下一个元素。
2、筛选函数出现报错,调试后发现指针在结点删除后变成空指针,未重新指向下一个结点,导致报错。
五、用户使用说明
一、本程序运行环境为Windows操作系统下的Microsoft Visual C++ 6.0。
二、在VC环境下打开程序后,输入整数,并用一个空格分隔,敲击“回车符”输入,即可以显示要求的结果。
三、按下任意键以继续。
六、测试结果
七、附录
#include<stdio.h>
#include<stdlib.h>
#define TRUE 1
#define FALSE 0
#define OK 1
#define ERROR 0
typedef int Status; /**Status是函数类型,其值是函数结果状态代码,如OK等*/
typedef int ElemType;
/**顺序表的定义*/
typedef struct LNode{ // 结点类型
ElemType data; //数据域
struct LNode *next; //指针域
} *Link, *Position;
typedef struct { // 链表类型
Link head; // 头结点
Link tail; // 最后一个结点
int len; // 线性链表中的数据元素格式
} LinkList;
Status MakeNode(Link &p, ElemType e){
// 分配由p指向的值为e的结点。若分配失败,则返回ERROR
p = (Link)malloc(sizeof(LNode));
if(!p){
return ERROR;
}
p->data = e;
}
void FreeNode(Link &p){
// 释放p所指结点
free(p);
p = NULL;
}
Status InitList(LinkList &L){
// 构造一个空的线性链表L
Link p;
p = (Link)malloc(sizeof(LNode)); // 生成头结点
if(p){
p->next = NULL;
L.head = L.tail = p;
L.len = 0;
}
else
return ERROR;
}
void ClearList(LinkList &L){ // 将线性链表L重置为空表,并释放原链表的结点空间
Link p,q;
if(L.head!=L.tail) // 不是空表
{
p=q=L.head->next;
L.head->next=NULL;
while(p!=L.tail)
{
p=q->next;
free(q);
q=p;
}
free(q);
L.tail=L.head;
L.len=0;
}
}
Status DestroyList(LinkList &L){ // 销毁线性链表L,L不再存在(见图2.44)
ClearList(L); // 清空链表
FreeNode(L.head);
L.tail=NULL;
L.len=0;
}
Status InsFirst(LinkList &L,Link s){ // 形参增加L,因为需修改L
// h指向L的一个结点,把h当做头结点,将s所指结点插入在第一个结点之前
Link h = L.head;
s->next=h->next;
h->next=s;
if(h==L.tail) // h指向尾结点
L.tail=h->next; // 修改尾指针
L.len++;
}
Status Compare(Link p1, Link p2) {
if(p1->data > p2->data){
return TRUE;
}else{
return FALSE;
}
}
void ExchangeData(Link &p1,Link &p2){ // 已知p指向线性链表中的一个结点,用e更新p所指结点中数据元素的值
ElemType temp = p1->data;
p1->data = p2->data;
p2->data = temp;
}
ElemType GetCurElem(Link p){ // 已知p指向线性链表中的一个结点,返回p所指结点中数据元素的值
return p->data;
}
void sort(LinkList &L){
for (int i = 0; i < L.len; i++)
{
Link p2 = L.head->next;
if(p2->next==NULL){
return;
}
Link p1 = L.head->next->next;
for (int j = 0; j <= L.len-2; j++)
{
if(Compare(p1,p2)){
ExchangeData(p1, p2);
}
p1 = p1->next;
p2 = p2->next;
}
}
}
Status DeleteNode(LinkList &L, Link s){
if(s == L.head || L.head == L.tail){
return FALSE;
}
if(s == L.tail){
Link p = L.head;
while(p->next!=L.tail){
p = p->next;
}
p->next = NULL;
L.tail = p;
FreeNode(s);
L.len--;
return TRUE;
}
Link p = L.head;
while(p->next!=s){
p = p->next;
}
p->next = p->next->next;
FreeNode(s);
L.len--;
return TRUE;
}
void PrintList(LinkList &L){
Link p = L.head->next;
for (int i = 0; i < L.len; i++)
{
printf("%d ", p->data);
p = p->next;
}
}
void Function_1(LinkList &L, int mink, int maxk){
//筛选出指定范围的数据
Link p1 = L.head;
while (p1->next!=NULL)
{
Link p2 = p1;
p1 = p1->next;
if(p1->data<mink || p1->data>maxk){
DeleteNode(L, p1);
p1 = p2;
}
}
}
void Function_2(LinkList &L_A, LinkList &L_B, LinkList &L_C){
//分离出奇数和偶数
Link p = L_A.head;
while (p->next!=NULL)
{
p = p->next;
if (p->data%2==1)
{
Link s;
MakeNode(s, p->data);
InsFirst(L_B, s);
}
else
{
Link s;
MakeNode(s, p->data);
InsFirst(L_C, s);
}
}
}
int main(){
LinkList L_A, L_B, L_C;
InitList(L_A);
InitList(L_B);
InitList(L_C);
char a;
int b;
scanf("%d", &b);
scanf("%c", &a);
while (a!='\n')
{
Link p;
MakeNode(p, b);
InsFirst(L_A, p);
scanf("%d", &b);
scanf("%c", &a);
}
Link p;
MakeNode(p, b);
InsFirst(L_A, p);
sort(L_A);
Function_1(L_A, 0, 20);
Function_2(L_A, L_B, L_C);
sort(L_B);
sort(L_C);
printf("\nL_A:");
PrintList(L_A);
printf("\nL_B:");
PrintList(L_B);
printf("\nL_C:");
PrintList(L_C);
}