#include <stdlib.h>
#include <stdio.h>
#define LEN sizeof(DAT)
#define TRUE 1
#define FALSE -1
#define NULL 0
typedef struct LNode{
int data;
struct LNode *next;
}DAT;
void InitList(DAT *head)//创建空表
{
head = (DAT *)malloc(LEN);
if(!head)
{printf("\n--链表创建失败--\n");exit(FALSE);}
head ->next = NULL;
}
DAT *creatList(DAT *head)//数据录入
{
DAT *p1,*p2;
char ch;
int n = 1;
head = (DAT *)malloc(LEN);
p1 = p2 = (DAT *)malloc(LEN);
if(p1 != NULL)
{
printf("\n请输入数据:\n");
scanf("%d",&p1->data);//p1需要存储数据,每一次存储都需要申请空间
head -> next = p1;//注意:本程序的头结点不存储数据,因为ClearList函数和destroyList函数无法区分实现
//所以ListTraverse输出函数也是从头结点的下一个才开始输出的!
//p2 = p1;为什么这步可以省略呢?就是因为p1,p2在申请空间的时候被赋予的地址是一致的!
printf("\n继续录入(y/any other keys to exit)?\n");
getchar();
scanf("%c",&ch);
while(ch == 'Y'||ch == 'y')
{
printf("\n请输入数据:\n");
p1 = (DAT *)malloc(LEN);
if(p1 != NULL)
scanf("%d",&p1->data);
p2 -> next = p1;
p2 = p1;
printf("\n继续录入(y/any other keys to exit)?\n");
getchar();
scanf("%c",&ch);
}
p2 -> next = NULL;//p2作为连接新建节点的指针,如果next为空,那自然是结束了录入
printf("\n--录入结束--\n");
}
return head;
}
int ClearList(DAT *head) //保留头结点,其余节点数据清空
{
if(head == NULL)
{
printf("\n--表不存在--\n");
return FALSE;
}
DAT *p,*q;
p = head -> next;
while(p)
{
q=p->next;//用声明的另一个指针q来记录p的下一节点的位置
printf("\n--已删除表中数据:%d--\n",p -> data);
free(p);
p=q;//结合q = p -> next,此语句的作用即是让p往后移动,从而实现逐个清空数据的目的
}//直至p为空的时候便是结束了循环,清空结束
head -> next = NULL; //数据清空之后头结点的指针域为空
return TRUE;
}
DAT *destroyList(DAT *head)//与清空链表函数不同,销毁需要把头结点也一同清除,清楚后将无法再录入数据
{
if(head == NULL)
{
printf("\n--表不存在,销毁无效--\n");
exit(FALSE);
}
DAT *p;
p = head;
while(head)
{
p = head -> next;
free(head);//第一次循环的时候清除了头结点
head = p;
}
printf("\n--链表销毁结束--\n");
return head;
}
int ListLength(DAT *head)
{
DAT *p;
int i = 0;
p = head -> next;
while(p)
{
i++;
p = p -> next;
}
printf("\n--链表长度为:%d--\n",i);
return i;
}
void ListTraverse(DAT *head)//输出函数
{
DAT *p = head -> next;
DAT *q = p;//位序输出遍历需要
int n = 0;
int length = ListLength(head);
if(p)
{
printf("\n位序 | ");
for(n = 1;n <= length;n++)
{
if(q -> data <10)
printf("%d ",n);
else if(q -> data <100)
printf("%2d ",n);
else
printf("%3d ",n);
q = q -> next;
}
printf("\n------------------------------------\n");
printf("数据 | ");
do
{
printf("%d ",p -> data);
p = p -> next;
}
while(p);
}
printf("\n");
}
int GetElem(DAT *head,int i,int e)
{
int n = 1;
DAT *p;
p = head ->next;
while(p && n < i )//当p不为空且初始位序小于查找位序的时候
{
p = p -> next;//指针后移,直至与查找位序相等为止推出循环
n++;
}
if(!p || n > i)
{printf("\n--找不到该位序--\n");return FALSE;}
e = p -> data;
return e;
}
int LocateElem(DAT *head,int e)//查找e的位序,并将其位序返回
{
DAT *p;
int i = 1;
printf("\n请输入你要查找的数据:\n");
scanf("%d",&e);
p = head -> next;
while(p)
{
if(p -> data == e)
{
printf("\n--%d的位序为:%d--\n",e,i);
return i;
}
else
p = p -> next;
i++;
}
printf("\n--找不到该元素--\n"); return 0;
}
int PirrorElem(DAT *head,int cur_e,int pre_e)//查找元素的前驱
{
printf("\n请输入表中数据,系统将会返回其的前驱:\n");
scanf("%d",&cur_e);
if(head == NULL)
{
printf("\n--表不存在--\n");
return FALSE;
}
DAT *p,*q;
q = head -> next;//q指向第一个节点
while(p)
{
p = q -> next;//p指向q的下一节点
if( q -> data == cur_e)//cur_e为第一个元素的时候,提示错误
{
printf("\n--表中第一个元素是没有前驱的,无法查找--\n");
return FALSE;
}
if(p -> data == cur_e)//如果p指针找到了cur_e,就用q返回前驱
{
pre_e = q -> data;
printf("\n--%d的前驱是:%d--\n",cur_e,pre_e);
return pre_e;
}
else
{
if( p -> next != NULL)
q = p;//p,q指针相连,q后移也会带动p的后移
else// p遍历结束达到NULL的时候即是没有找到输入的数据,提示错误
{
printf("\n--表中无此数据--\n");
return FALSE;
}
}
}
}
int NextElem(DAT *head,int cur_e,int next_e)//查找元素的后继
{
DAT *p,*q;
printf("\n请输入数据,系统将会返回其的后继:\n");
scanf("%d",&cur_e);
p = head -> next;
while(p)
{
q = p -> next;
if( p -> data == cur_e && p -> next != NULL)//p没有下一节点的话,也就没有后继之说了
{
next_e = q -> data;
printf("\n-%d的后继为:%d--\n",cur_e,next_e);
return next_e;
}
if( p -> data != cur_e)
{
p = q;//p -> next 不为空的时候,p,q后移遍历
if( p -> next == NULL && p -> data == cur_e )//判断是否有后继
{
printf("\n--末位的数据是没有后继的,无法查找--\n");
return FALSE;
}
if( p -> next == NULL && p ->data != cur_e)//判断时候存在cur_e
{
printf("\n--表中不存在该元素--\n");
return FALSE;
}
}
}
}
DAT *ListInsert(DAT *head,int i,int e)//按位序i插入特定元素e
//定义结构体指针函数,用于返回结构体指针head
{
printf("\n请输入插入的位序和元素\n");
scanf("%d%d",&i,&e);
DAT *p = head;//和下面n = 0相对应,head无数据
DAT *q;
int n = 0;
while(p != NULL && n < i-1)//找到i的前一个节点
{
p = p -> next;//循环第一次的时候p便指向了第一个节点,和n=1对应
n++;//n = 1
}//出循环时n=i-1,p也就指向了i的前一位序
if(p == NULL || n > i-1)//i过大(插入的位序的前一个如果还是空的话,那就超出了插入范围)或过小的时候报错,退出
{
printf("\n--位序错误,插入失败--\n");
return head;
}
q = (DAT *)malloc(LEN);//新节点空间申请
q -> data = e;//新节点赋值
q -> next = p->next;//新节点定位(p -> next为第i个节点),将新节点与原表中第i个节点相连,即是替换了第i的位置
//如果是表尾插入的话,q -> next == NULL
p -> next = q;//再将新节点与前面的p节点相连,即完成了插入
printf("\n--%d已添加到表中第%d位序--\n",e,i);
return head;//返回头指针,方便打印链表
}
DAT *ListInsert_last(DAT *head,int e)//表尾插入函数
//定义结构体指针函数,用于返回结构体指针head
{
int leng = ListLength(head);
DAT *p = head;//和下面n = 0相对应,head无数据
DAT *q;
int n = 0;
while(p != NULL && n < leng)//找到尾节点,在尾节点的后一节点添加数据
{
p = p -> next;//循环第一次的时候p便指向了第一个节点,和n=1对应
n++;//n = 1
}//出循环时n=leng,p也就指向了表尾
if(p == NULL || n > leng)//i过大(插入的位序的前一个如果还是空的话,那就超出了插入范围)或过小的时候报错,退出
{
printf("\n--位序错误,插入失败--\n");
return head;
}
q = (DAT *)malloc(LEN);//新节点空间申请
q -> data = e;//新节点赋值
q -> next = p->next;//新节点定位(p -> next为第i个节点),将新节点与原表中第i个节点相连,即是替换了第i的位置
//如果是表尾插入的话,q -> next == NULL
p -> next = q;//再将新节点与前面的p节点相连,即完成了插入
printf("\n--%d已添加到表尾--\n",e);
return head;//返回头指针,方便打印链表
}
DAT *ListDelete(DAT *head,int i,int e)
{
printf("\n请输入你要删除的位序:\n");
scanf("%d",&i);
DAT *p = head;
DAT *q;
int n = 0;
while(p -> next != NULL && n < i - 1)//循环是为了找到要删除的节点的前驱,即p指向删除节点的上一个节点
{
p = p -> next;
n++;
}
if(p -> next == NULL || n > i -1)//i过大或过小的时候报错退出(要删除的节点不能为空)
{
printf("\n--位序错误,删除失败--\n");
return head;
}
q = p -> next;//q指向p的下一节点
p -> next = q -> next;//将p的下一节点绕到q的下一节点上去,完成对q节点的孤立,将q节点删除
e = q -> data;//用e返回被删除的节点上的数据
free(q);
printf("\n--表中第%d位序上的数据:%d已被删除--\n",i,e);
return head;
}
#include "E.h"
void main()
{
//DAT *head;
//int i,e;
//int cur_e;
//int pre_e;
//int next_e;
//开始测试函数
//InitList(head);//创建空表
//head = creatList(head);//输入数据
//ListTraverse(head);//输出数据
//ListLength(head);//输出链表长度
//ClearList(head);//清空数据
//ListTraverse(head);//输出清空效果
//destroyList(head);
//ListTraverse(head);
//printf("\n请输入你要查找的位序:\n");
//scanf("%d",&i);
//e = GetElem(head,i,e);
//if(e != FALSE)
//printf("\n--位序%d上的数据为:%d--\n",i,e);
//PirrorElem(head,cur_e,pre_e);
//NextElem(head,cur_e,next_e);
//head = ListInsert(head,i,e);
//head = ListDelete(head,i,e);
//ListTraverse(head);*/
//用自建函数合并两个不同数据的链表
DAT *L1 = NULL;
DAT *L2 = NULL;
DAT *L3 = NULL;
DAT *p1 = NULL;
DAT *p2 = NULL;
DAT *p3 = NULL;
DAT *p4 = NULL;
DAT *p5 = NULL;
int n = 0;
int m = 0;
int leng1;
int leng2;
int leng3;
int i = 0,j = 0,k = 0;
InitList(L1);
InitList(L2);
L1 = creatList(L1);
p1 = L1;
ListTraverse(L1);
L2 = creatList(L1);//录入两个链表数据
p2 = L2;
ListTraverse(L2);
leng1 = ListLength(L1);
leng2 = ListLength(L2);//链表长度获取
L3 = (DAT *)malloc(sizeof(DAT));//第三链表的建立,用于存储表一和表二中不重复的数据
p3 = p4 = (DAT *)malloc(sizeof(DAT));
if(leng1 >= leng2)
{
for(i = 0;i < leng2;i++)
{
if(p2 -> next != NULL)
{p2 = p2 -> next;}
for(j = 0; j < leng1;j++)
{
if(p1 -> next != NULL)
{
p1 = p1 -> next;
}
else//p1 -> next ==NULL的时候
{
p1 = L1 -> next;//重置p1回到L1的第一个节点
}
if(p2 -> data != p1 -> data)//表三数据链表的录入
{ printf("\n--%d--\n",p2->data);
printf("\n-|%d|-\n",p1->data);
m++;
printf("\nm = %d\n",m);
if(m == leng1)//将表二的一个数对比表一中所有的数,如果都不一样则将这个数插入表三
{
p3 -> data = p2 -> data;
if(p3 -> data != NULL)
{
n++;
if(n == 1)
L3 -> next = p3;
else
p4 -> next = p3;
p4 = p3;
p3 = (DAT *)malloc(sizeof(DAT));
}
p4 -> next = NULL;
m = 0;//重置m
}
}
}
if(m <leng1)//m小于leng1说明有数重复,为了下一个数的比较可以顺利进行,标志m也要重置
m=0;
}
//因为是很久以前的数据结构作业,源文件已经找不到了,还好QQ空间当初留有图片(下面的图片衔接上一部分)
//少了一个花括号
}