数据结构线性表链表的C语言实现
说明:线性表是一种最简单的线性结构,也是最基本的一种线性结构,所以它不仅是学习中的重点,也是应用开发非常常用的一种数据结构。它可以分为顺序表和链表。它的主要操作是数据元素的插入,删除,以及排序等。接下来,本篇文章将对线性表链表的基本操作和运用进行详细的说明(包含在源代码的注释中),并给予可运行的程序源代码。
线性表链表不同于顺序表,它是一种链式的线性表,和顺序表的类似数组的存储特点不同,它是一个个独立的存储单元,中间用指针链接,类似一条链子,所以叫链表。因为同属线性表所以它的基本操作与顺序表是一致的,所以基本操作函数名相同但是具体实现方式不同,顺序表的优点在于它可以随机存储数据元素,但在删除和插入操作时需要移动大量元素。而链表则相反,它无法做到随机存取,但在进行删除和插入操作时非常方便,仅需要修改下指针并释放被删除元素的存储空间而已。
程序分析:由于抱着是程序执行起来时操作尽量简单化,使人一看就能明白,所以本程序是用了不少的提示性语句。主函数的结构是while循环和switch函数相结合的方法,使每种能够用到的基本操作尽量明白的显示在主显示函数中,这样能使每种基本操作的作用效果更加突出明了。这样不仅能使程序的模块化尽量明显,也可以让源代码的可读性增强。而且程序运用了CLS清屏函数,可以使每一次操作的输入输出结果更加清晰。
源代码:
#include<stdio.h>
#include<stdlib.h>
#include<malloc.h>
#define OK 1
#define ERROW -1
#define OVERFLOW -2
#define LEN sizeof(struct Lnode)
#define LN LNode *
typedef int Status;
typedef int ElemType;
/*链表的结点的数据结构 */
typedef struct Lnode
{
ElemType num; //为求简便数据域仅置一项
struct Lnode *next;
}LNode,*LinkList; // *LinkList L 定义链表头指针
/*链表的初始构建函数*/
Status InitList(LinkList &L)
{
L=(LN)malloc(LEN);
if(L==0)
exit(OVERFLOW);
L->next=NULL;
return OK;
}
/*链表的清空涵数*/
void ClearList(LinkList &L)
{
LinkList p;
while(L->next)
{
p=L->next;
L->next=p->next;
free(p);
}
// 最终效果是只保留头节点
}
/*销毁函数*/
void DestoryList(LinkList &L)
{
ClearList(L);
free(L); //释放头节点空间
L=NULL;//链表的变量归于初始值,便于识别和处理
}
/*取表长函数*/
Status GetLength(LinkList L)
{
int n;
n=0;
if(L==NULL)//未经初始构建函数构建或已经彻底销毁
return n;
while(L->next)
{
L=L->next;
n++;
}
return n;
}
/*判断表的空否的函数 */
Status IsEmpty(LinkList L)
{
if(L->next==NULL)
return OK;
else
return ERROW;
}
/*定位取值函数*/
Status GetElem(LinkList L,int i,ElemType &e)
{
int j=1;
LinkList p;
p=L->next;
while(p&&j<i)
{
p=p->next;
j++;
}
if(p==NULL||j>i) //所给位置序号超出表长
{
printf("序号输入错误!\n\n");
return ERROW;
}
e=p->num;
return OK;
}
/*查找定位函数*/
Status LocateElem(LinkList L,int &i,ElemType e)
{
i=1;
LinkList p;
p=L->next;
while(p&&p->num!=e)
{
p=p->next;
i++;
}
if(p!=NULL)
return OK;
else
return ERROW;
}
/*创建一个链表*/
void ScanList(LinkList &L)
{
int i;
LinkList p,p0;
if(L==NULL)
InitList(L);
p0=L;
printf("请输入链表长度\n");
scanf("%d",&i);
printf("\n请输入%d个数\n",i);
for(;i>0;i--)
{
p=(LN)malloc(LEN);
p->next=NULL;
scanf("%d",&p->num);
p0->next=p;
p0=p;
}
}
/*输出表中所有数据元素*/
void PrintList(LinkList L)
{
LinkList p0;
p0=L->next;
printf("\n");
while(p0!=NULL)
{
printf("%d ",p0->num);
p0=p0->next;
}
printf("\n");
}
/*数据元素插入函数*/
Status ListInsert(LinkList &L,int i,ElemType e)
{
int j=0;
LinkList p,p0;
p=L;
while(p&&j<i-1)
{
p=p->next;
j++;
}
if(p==NULL||j>i)
{
return ERROW;
}
p0=(LN)malloc(LEN);
p0->num=e;
p0->next=p->next;
p->next=p0;
return OK;
}
/*定位删除函数*/
Status ListDelete_1(LinkList &L,int i)
{
int j=0;
LinkList p,p0;
p=L;
while(p&&j<i-1)
{
p=p->next;
j++;
}
if(p==NULL||j>i)
{
return ERROW;
}
p0=p->next;
p->next=p0->next;
free(p0);
return OK;
}
/*非递减冒泡排序函数*/
int maopao(LinkList &L)
{
int i,j,t,n;
LinkList p,p0;
p0=L;
n=GetLength(L);
for(j=1;j<=n-1;j++)
{
p0=p0->next;
p=p0;
for(i=1;i<=n-j;i++)
{
if(p->num>p->next->num)
{
t=p->num;
p->num=p->next->num;
p->next->num=t;
}
p=p->next;
}
}
return OK;
}
/*主提示函数*/
void printlin()
{
printf("\n");
printf("\t\t\t线性链表基本操作学习系统\n");
printf("\t\t\t ***主菜单***\n\n");
printf("\t\t\t *1 创建一个链表表\n");
printf("\t\t\t *2 定位输出一个数据元素\n");
printf("\t\t\t *3 输出链表中所有元素\n");
printf("\t\t\t *4 定位插入一个数据元素\n");
printf("\t\t\t *5 定位删除一个数据元素\n");
printf("\t\t\t *6 定值删除一个数据元素\n");
printf("\t\t\t *7 清空链表\n");
printf("\t\t\t *8 销毁链表\n");
printf("\t\t\t *9 对表内数据元素进行非递减排序\n");
printf("\t\t\t *0 结束程序\n");
}
int main()
{
int i,j,k;
LinkList L;
L=NULL;
printf("编写此程序目的是自我学习线性表链表\n");
printlin();
while(1)
{
int t;
scanf("%d",&t);
if(t!=0)
if(t==1||GetLength(L)!=0)
{
switch(t)
{
case 1: if(GetLength(L)!=0)
{
printf("链表已存在,是销毁并重新创建链表?\n");
printf("*1 是 *2 否\n");
scanf("%d",&i);
if(i==1)
{
DestoryList(L);
ScanList(L);
}
}
else
ScanList(L);
break;
case 2: {
k=GetLength(L);
printf("请输入数据位置\n");
scanf("%d",&i);
if(i<1||i>k)
printf("输入位置错误\n");
else
{
GetElem(L,i,j);
printf("第%d个数为%d\n",i,j);
}
break;
}
case 3: PrintList(L);break;
case 4: {
printf("输入要插入的位置\n");
scanf("%d",&i);
printf("请输入要插入的数据\n");
scanf("%d",&j);
k=ListInsert(L,i,j);
if(k==-1)
printf("插入位置不合法,插入数据操作失败!\n\n");
else
printf("插入数据成功\n\n");
break;
}
case 5: {
printf("请输入要删除数据位置\n");
scanf("%d",&i);
k=ListDelete_1(L,i);
if(k==-1)
printf("输入位置错误,删除操作失败!\n\n");
else
printf("删除成功!\n\n");
break;
}
case 6: {
printf("请输入需要删除的元素:\n");
scanf("%d",&j);
k=LocateElem(L,i,j);
if(k==-1)
printf("未找到该元素,删除操作失败!\n\n");
else
{
ListDelete_1(L,i);
printf("删除成功!\n\n");
}
break;
}
case 7: {
ClearList(L);
printf("清空完毕,返回主菜单\n\n");
break;
}
case 8: {
DestoryList(L);
printf("销毁成功,返回主菜单\n\n");
break;
}
case 9: {
maopao(L);
printf("已成功排序,返回主菜单\n\n");
break;
}
case 0: break;
default: {
printf("输入有误,可以重新选择,退出按0!\n\n");
}
}
}
else
printf("链表未创建或已清空或销毁,请先创建链表\n\n");
system("pause");
system("CLS");
printlin();
if(t==0)
break;
}
return 0;
}
程序运行效果图 (部分):
图 1
图2
图3
图4
结束语:纸上得来终觉浅,绝知此事要躬行!