您的位置:首页 > 其它

线性表的链式存储

2015-03-13 15:18 330 查看
线性表的链式存储。主要是单链表的相关知识,介绍了正序建立单链表、逆序建立单链表、单链表的插入、删除、查找、输出以及单链表的合并方法。单链表的合并前提是两个都有序。具体知识点详见代码注释。

/***
线性表的链式存储结构不能随机存储,整个链表的存取都必须从头结点开始。但是没有顺序存储的缺点:插入或者删除时需要移动大量元素
其特点是用一组任意的存储空间存储线性表的数据元素

结点:数据域和指针域
*/
#include<stdio.h>
#include<stdlib.h>
#define MAX 100000
//**********************线性表的单链表存储结构***********************
typedef struct LNode
{
int data;            //数据域
struct LNode *next;  //指针域
} LNode,*LinkList;       //LinkList是LNode型结构的指针

//**************************头插法逆序建立单链表****************************
void CreateList_L1(LinkList &L,int n)
{
//逆位序输入n个元素值,建立带有头结点的单链表,时间复杂度为O(n)
L->next = NULL;//先建立个带有头结点的单链表L,使头结点指针域为空,
for (int i = n; i > 0; --i)
{
LinkList p = (LinkList)malloc(sizeof(LNode));//生成新结点
scanf("%d",&p->data);
//插入到表头
p->next = L->next;
L->next = p;
}

}

//**************************尾插法正序建立单链表****************************
void CreateList_L2(LinkList &L,int n)
{
//借助一个中间变量,正序建立n个元素的单链表,时间复杂度仍然为O(n)
//先建立个带有头结点的单链表L,头结点指针域为空,默认使用Linklist建立L是即为空
LinkList r = L;
for (int i = 0; i < n; ++i)
{
LinkList p = (LinkList)malloc(sizeof(LNode));//生成新结点
scanf("%d",&p->data);
//插入到表尾
r->next = p;
r = p;
}
r->next = NULL;
}

//**************************按序输出单链表的各个元素****************************
void PrintList_L(LinkList L)
{
LinkList p = L->next;//p指向第一个元素
while(p)
{
printf("%d ", p->data);
p = p->next;
}
}

//***********************取出指定位序的单链表中的数据元素***********************
int  GetElem_L(LinkList L,int i)
{
//时间复杂度为O(n)
//L为带头结点的单链表的头指针
//返回链表的第i个元素,若没有,则错误提示
LNode *p = L->next; //初始化,p指向第一个结点
int j = 1;//计数器
int e;//返回值
while(p && j<i)
{
//顺指针向后查找,知道p指向第i个元素或者p为空
p = p->next;
++j;
}
if (!p || j>i)
{
printf("没有找到该元素,请确认后重新输入位序!\n");
e = MAX;
return e;
}
e = p->data;
return e;
}

//*******************向单链表的指定位序插入一个元素********************
void ListInsert_L(LinkList &L,int i,int e)
{
//在带头结点的单链表L的第i个位置之前插入元素e,1=<i<=length(L)+1,时间复杂度为O(n)
/*
LNode *p = L->next; //初始化,p指向第一个结点,下面一句话效果一样,因为LinkList是指向LNode型的指针变量,无需再加*号
LinkList p = L->next;
int j = 1;//计数器
*/
//上面使p指向第一个结点的方法有问题,如果要将元素插在第一位会有bug,故要从头结点开始
LinkList p = L;
int j = 0;
while(p && j<i-1)
{
p = p->next; //寻找第i-1个结点,使p指向它
++j;
}
if (!p || j>i-1)
{
printf("要插入的位置没有找到,可能是插入位序有误!\n");
getchar();
exit(1);
}
LinkList s = (LinkList)malloc(sizeof(LNode));//生成一个结点s
s->data = e;
//插入结点
s->next = p->next;
p->next = s;
}

//********************删除单链表的指定位序的一个元素********************
void ListDelete_L(LinkList &L,int i)
{
//时间复杂度为O(n)
//在带头结点的单链表L中,删除第i个位置的元素.i<=length(L)
LNode *p = L; //初始化,p指向头结点
int j = 0;//计数器
while(p->next && j<i-1)
{
p = p->next; //使p指向被删除结点的前一个结点,即p指向i-1
++j;
}
if (!(p->next) || j>i-1)
{
//要保证p的后一个元素有值,即被删除元素存在
printf("删除位置不合理,请重新确认!\n");
getchar();
exit(1);
}
//删除该元素
LNode *q = p->next;
p->next = q->next;
free(q);//释放结点
}

//**************************有序链表的合并******************************
void MergeList_L(LinkList &La,LinkList &Lb,LinkList &Lc)
{
//已知单链线性表La和Lb的元素按值非递减排序
//归并La和Lb得到新的单链表Lc,Lc的元素也按值非递减排列
LinkList pa,pb,pc;
pa = La->next;
pb = Lb->next;
//用La的头结点作为Lc的头结点
pc = La;
Lc = pc;
while(pa && pb)
{
if (pa->data <= pb->data)
{
pc->next = pa;
pc = pa;
pa = pa->next;
}
else
{
pc->next = pb;
pc = pb;
pb = pb->next;
}
}
pc->next = pa?pa:pb;
free(Lb);//释放Lb的头结点
}

int main()
{
//定义3个链表,初始化3个头结点
LinkList la = (LinkList)malloc(sizeof(LNode));
LinkList lb = (LinkList)malloc(sizeof(LNode));
LinkList lc;//
int count;//计数使用,链表初始化时记录链表元素个数
int location,value;//插入时的位置和值
char c;
//使用头插法逆序建立链表
printf("请输入la链表元素个数:");
scanf("%d",&count);
CreateList_L1(la,count);
printf("逆序建立的la链表元素为:");
PrintList_L(la);

//使用尾插法正序建立链表
printf("\n\n请输入链表lb元素个数:");
scanf("%d",&count);
CreateList_L2(lb,count);
printf("正序建立的lb链表元素为:");
PrintList_L(lb);

//向正序建立的单链表中插入数据
printf("\n\n请输入lb插入位置和插入值:");
scanf("%d%d",&location,&value);
ListInsert_L(lb,location,value);
printf("插入元素之后的链表元素为:");
PrintList_L(lb);

//继续测试该链表的删除效果
printf("\n\n请输入lb删除位置:");
scanf("%d",&location);
ListDelete_L(lb,location);
printf("删除元素之后的链表元素为:");
PrintList_L(lb);

//测试GetElem函数是否有效
printf("\n\n请输入需要得到的元素位置:");
scanf("%d",&location);
value = GetElem_L(lb,location);
if (value == MAX)
{
printf("输入错误或者没有该位置的元素!\n");
}else
{
printf("该元素的值为:%d",value);
}

//测试两个链表的归并,前提是两个链表都有序
MergeList_L(la,lb,lc);
printf("\n\n两个链表合并后lc的元素是:");
PrintList_L(lc);

return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: