您的位置:首页 > 理论基础 > 数据结构算法

写给初学者的数据结构——初识链表(带头结点)(标准C实现)

2019-07-12 16:11 281 查看
版权声明:本文为博主原创文章,遵循 CC 4.0 by-sa 版权协议,转载请附上原文出处链接和本声明。 本文链接:https://blog.csdn.net/weixin_43796828/article/details/95616496

 全文一共3195字,理解部分大约需要15分钟的阅读时间,感谢遇见!

目录

1、相关文章

2、理解

3、示例

4、完整测试源码

5、运行截图

1、相关文章

C++(理解篇):https://www.geek-share.com/detail/2773834387.html(推荐优先阅读)

Java:https://blog.csdn.net/weixin_43796828/article/details/95611547

2、理解:

C实现与C++实现的区别在于:C++采用了引用调用的参数传递方式,而标准C不支持。

高一凡《数据结构》中,有这样一段话。

所以,将C++函数中形参表中以&打头的参数改成以*打头的参数,再将函数中该参数前加*即可。另外,调用该函数,实参前应加&。

3、示例:

[code]Status CreatDescend(LinkList &L,int n)
{
//按非升序建立n个元素的线性表
int j;
LinkList p,q,s;

if(n<=0)
{
return ERROR;
}

InitList(L);
printf("请输入%d个元素:\n",n);

s = (LinkList)malloc(sizeof(struct LNode));		//第一个结点
scanf("%d",&s->data);
s->next = NULL;
L->next = s;

for(j=1; j<n; j++)
{
s = (LinkList)malloc(sizeof(struct LNode));	//其余节点
scanf("%d",&s->data);
q = L;
p = L->next;
while(p&&p->data>s->data)
{
q = p;
p = p->next;						//指针后移
}
s->next = q->next;						//元素插在q的后面
q->next = s;
}

return OK;
}

 

[code]CreatAscend(L,n);
[code]Status CreatAscend(LinkList *L,int n)
{
//按非降序建立n个元素的线性表
int j;
LinkList p,q,s;

if(n<=0)
{
return ERROR;
}
InitList(*L);
printf("请输入%d个元素:\n",n);

s = (LinkList)malloc(sizeof(struct LNode));		//第一个结点
scanf("%d",&s->data);
s->next = NULL;
(*L)->next = s;

for(j=1; j<n; j++)
{
s = (LinkList)malloc(sizeof(struct LNode));	//其余结点
scanf("%d",&s->data);
q = *L;
p = (*L)->next;

while(p && p->data<s->data)
{
q = p;
p = p->next;						//指针后移
}
s->next = q->next;						//元素插在q的后面
q->next = s;
}

return OK;
}
[code]CreatAscend(&L,n);

其中,再调用两程序中,实参L的类型是相同的。还有,在转换过程中,遇到&*或*&可“抵消”,即将*&T转换为T。

我的理解:将实参(地址)传递给一个二维指针,函数中用这个参数,前面加一个*号,意味着调用二维指针所指向的内容,也就是一维指针。&*可以相互抵消,但是我们都看到了,C程序里调用L的时候前面都加了*号。也就是说,&*可以相互抵消,但是原来的参数调用方式可能会有所改变。

4、完整测试源码:

[code]#include<stdio.h>
#include<math.h>					//储存着OVERFLOW,值为3
#include<stdlib.h>
typedef int ElemType;
typedef int Status;
typedef int Boolean;

#define TRUE 	    1
#define FALSE 	    0
#define OK          1
#define ERROR 	    0
#define	INFEASIBLE -1

struct LNode
{
ElemType data;
struct LNode *next;
};

typedef struct LNode* LinkList;

Status InitList(LinkList *L)							//操作结果: 构造一个空的线性表L
{
(*L) = (LinkList)malloc(sizeof(struct LNode));			//产生头结点,并使L指向此头结点

if(!(*L))												//存储分配失败
{
exit(OVERFLOW);
}
(*L)->next = NULL;

return OK;
}

Status ListInsert(LinkList L,int i,ElemType e)			//在带头节点的单链线性表L中第i个位置之前插入元素e
{
int j = 0;
LinkList p = L,s;

while(p && j<i-1)			//寻找第i-1个结点,令p指向它。p指向第一个结点的时候,j为1.
{
p = p->next;
j++;
}//这里有两个终止条件,一个是链表遍历完了,一个是找到了

if(!p || j>i-1)				//如果遍历完了没找到
{
return ERROR;
}

s = (LinkList)malloc(sizeof(struct LNode));	//生成新节点
s->data = e; 								//插入L中
s->next = p->next;
p->next = s;

return OK;
}

Status ListDelete(LinkList L,int i,ElemType *e)			//在头结点的单链线性表l中,删除第i个元素,并由e返回其值
{
int j=0;
LinkList p=L,q;

while(p->next && j<i-1)			//寻找第i个结点,并令p指向其前趋,即第i-1个结点。p指向第一个结点的时候,j为1.
{
p = p->next;
j++;
}//与ListInsert对比一下?只有while里面的p->next不同

if(!p->next || j>i-1)				//删除位置不合理
{
return ERROR;
}

q = p->next;					//删除并释放节点
p->next = q->next;
*e = q->data;
free(q);

return OK;
}

Status DeleteElem(LinkList L,ElemType e)
{
//删除表中值为e的元素,并返回TRUE;如无次元素,则返回FALSE
LinkList p = L, q;
while(p)
{
q = p->next;
if(q && q->data==e)
{
p->next = q->next;
free(q);
return TRUE;
}
p = q;
}
return FALSE;
}

int LocateElem(LinkList L,ElemType e,Status(*compare)(ElemType,ElemType))
{
//初始条件:线性表L已存在,compare()是数据元素判定函数(满足为1,否则为0)
//操作结果:	返回L中第1个与e满足关系compare()的数据元素的位序.
//			若这样的元素不存在,则返回值为0

int i = 0;
LinkList p = L->next;

while(p)
{
i++;
if(compare(p->data,e))			//找到这样的数据元素
{
return i;
}
p = p->next;
}

return 0;
}

Status comp(ElemType c1,ElemType c2)
{
//数据元素判定函数(相等为TRUE,否则为FALSE)
if(c1==c2)
{
return TRUE;
}
else
{
return FALSE;
}
}

Status ReplaceElem(LinkList L,int i,ElemType e)		//用e取代表l中第i个元素的值
{
LinkList p = L;
int j = 0;
while(p->next && j<i) 							//j为1的时候p指向第一个结点
{
j++;
p = p->next;
}//这里有两个终止条件,一个是p指向空,即链表遍历完毕。另一个是j==i,即找到对应元素。

if(j==i)
{
p->data = e;
return OK;
}
else					//表中不存在第i个元素
{
return ERROR;
}
}

Status DestoryList(LinkList *L)
{
//初始条件: 线性表L已存在。
//操作结果: 销毁线性表L
LinkList p = *L;

while(p)
{
p = (*L)->next;
free(*L);
(*L) = p;
}
return OK;
}

Status ClearList(LinkList L)
{
//初始条件: 线性表L已存在.
//操作结果: 将L重置为空表
LinkList p,q;
p = L->next;		//p指向第一个结点
while(p) 			//没到表尾
{
q = p->next;
free(p);
p = q;
}
L->next = NULL;

return OK;
}

Status ListEmpty(LinkList L)
{
//初始条件:线性表L已存在。
//操作结果:若为空表,则返回FAlSE;
if(L->next) 		//非空
{
return FALSE;
}else
{
return TRUE;
}
}

int ListLength(LinkList L)
{
//初始条件: 线性表L已存在。
//操作结果: 返回L中数据元素的个数

int i = 0;
LinkList p = L->next;	//p指向第一个结点
while(p)				//没到表尾
{
i++;
p = p->next;
}
return i;
}

Status GetElem(LinkList L,int i,ElemType *e)
{
//L为带头结点的单链表的头指针
//当第i个元素存在时,其值赋给e并返回OK,否则返回ERROR

int j = 1;					//j为计数器
LinkList p = L->next ;		//p指向第一个结点

while(p && j<i)//p指向第2个结点时,j为2。所以j为i时,p指向第i个结点
{
p = p->next;
j++;
}

if(!p || j>i)				//第i个元素不存在
{
return ERROR;
}
*e = p->data;				//取第i个元素

return OK;
}

Status GetFirstElem(LinkList L,ElemType *e)//返回表头元素的值
{
LinkList p = L->next;
if(!p)
{
return ERROR;
}
else
{
*e = p->data;
}
return OK;
}

Status PriorElem(LinkList L,ElemType cur_e,ElemType *pre_e)
{
//初始条件: 线性表L已存在
//操作结果: 若cur_e是L的数据元素,且不是第一个,则用pre_e返回它的前驱。
//			返回OK;否则操作失败,pre_e无定义,返回INFEASIBLE

LinkList q,p = L->next;		//p指向第一个结点

while(p->next)				//p所指结点有后继
{
q = p->next;			//q为p的后继,实质是从第二个判到最后一个
if(q->data==cur_e)
{
*pre_e = p->data;
return OK;
}
p = q;
}

return INFEASIBLE;
}

Status NextElem(LinkList L,ElemType cur_e,ElemType *next_e)
{
//初始条件:线性表L已存在
//操作结果: 若cur_e是L的数据元素,且不是最后一个,则用next_e返回它的后继
//			返回OK;否则操作失败,next_e无定义,返回INFEASIBLE

LinkList p = L->next;		//p指向第一个结点
while(p->next)				//p所指结点有后继
{
if(p->data==cur_e)		//实质是从第一个判到倒数第二个
{
*next_e = p->next->data;
return OK;
}
p = p->next;
}

return INFEASIBLE;
}

void visit(ElemType c)
{
printf("%d ",c);
}

Status ListTraverse(LinkList L,void(*vi)(ElemType))
{
//初始条件: 线性表L已存在
//操作结果: 依次对L的每个数据元素调用函数vi().一旦vi()失败,则操作失败

LinkList p = L->next;
while(p)
{
vi(p->data);
p = p->next;
}
printf("\n");

return OK;
}

Status HeadInsert(LinkList L,ElemType e)
{
//初始条件:线性表L已存在。
//操作结果: 在L的头部插入新的数据元素e,作为链表的第一个元素

LinkList s;
s= (LinkList)malloc(sizeof(struct LNode));		//生成新结点
s->data = e;							//给结点赋值
s->next = L->next;						//插在表头
L->next = s;

return OK;
}

Status EndInsert(LinkList L,ElemType e)
{
//初始条件:线性表L已存在.
//操作结果:在L的尾部插入新的数据元素e,作为链表的最后一个元素

LinkList p = L;
while(p->next)				//使p指向表尾元素
{
p = p->next;
}

p->next = (LinkList)malloc(sizeof(struct LNode));			//在表尾生成新节点
p->next->data = e;									//给新节点赋值
p->next->next = NULL;								//表尾

return OK;
}

Status DeleteFirst(LinkList L,ElemType *e)
{
//初始条件: 线性表L已存在,且有不少于1个元素
//操作结果: 删除L的第一个数据元素,并由e返回其值

LinkList p=L->next;
if(p)
{
*e = p->data;
L->next = p->next;
free(p);
return OK;
}
else
{
return ERROR;
}
}

Status DeleteTail(LinkList L,ElemType *e)
{
//初始条件:	线性表L已存在,且有不少于1个元素
//操作结构: 删除L的最后一个数据元素,并用e返回其值

LinkList p=L,q;

if(!p->next)		//链表为空
{
return ERROR;
}

while(p->next)
{
q = p;
p = p->next;
}
q->next = NULL;		//新尾结点的next域设为NULL
*e = p->data;
free(p);

return OK;
}

void InsertAscend(LinkList L,ElemType e)
{
//初始条件: 按非降序排列的线性表L已存在。
//操作结果: 在L中按非降序插入新的数据元素e

LinkList q=L,p=L->next;
while(p&&e>p->data)
{
q = p;
p = p->next;
}
q->next = (LinkList)malloc(sizeof(struct LNode));	//插在q后
q->next->data = e;
q->next->next = p;
}

void InsertDescend(LinkList L,ElemType e)
{
//初始条件:按非升序排列的线性表L已存在.
//操作结果:在L中按非升序插入新的数据元素e

LinkList q = L,p = L->next;
while(p && e<p->data)
{
q = p;
p = p->next;
}
q->next = (LinkList)malloc(sizeof(struct LNode));	//插在q后
q->next->data = e;
q->next->next = p;
}

Status CreatAscend(LinkList *L,int n)
{
//按非降序建立n个元素的线性表
int j;
LinkList p,q,s;

if(n<=0)
{
return ERROR;
}
InitList(&(*L));
printf("请输入%d个元素:\n",n);

s = (LinkList)malloc(sizeof(struct LNode));		//第一个结点
scanf("%d",&s->data);
s->next = NULL;
(*L)->next = s;

for(j=1; j<n; j++)
{
s = (LinkList)malloc(sizeof(struct LNode));	//其余结点
scanf("%d",&s->data);
q = *L;
p = (*L)->next;

while(p && p->data<s->data)
{
q = p;
p = p->next;						//指针后移
}
s->next = q->next;						//元素插在q的后面
q->next = s;
}

return OK;
}

Status CreatDescend(LinkList *L,int n)
{
//按非升序建立n个元素的线性表
int j;
LinkList p,q,s;

if(n<=0)
{
return ERROR;
}

InitList(&(*L));
printf("请输入%d个元素:\n",n);

s = (LinkList)malloc(sizeof(struct LNode));		//第一个结点
scanf("%d",&s->data);
s->next = NULL;
(*L)->next = s;

for(j=1; j<n; j++)
{
s = (LinkList)malloc(sizeof(struct LNode));	//其余节点
scanf("%d",&s->data);
q = *L;
p = (*L)->next;
while(p&&p->data>s->data)
{
q = p;
p = p->next;						//指针后移
}
s->next = q->next;						//元素插在q的后面
q->next = s;
}

return OK;
}

int main()
{
LinkList L;
ElemType d,e;
Status i;
int n;

printf("按非降序建立n个元素的线性表L,请输入元素个数n: ");
scanf("%d",&n);

CreatAscend(&L,n);
printf("依次输出L的元素: ");
ListTraverse(L,visit);			//按非降序插入元素10

InsertAscend(L,10);
printf("按非降序插入元素10后,线性表L为: ");
ListTraverse(L,visit);

HeadInsert(L,12);				//在L的头部插入12
EndInsert(L,9);				//在L的尾部插入9
printf("在L头部插入12,尾部插入9后,线性表L为: ");
ListTraverse(L,visit);

i = GetFirstElem(L,&e);			//此句加
printf("第1个元素是:%d\n",e);	//此句加
printf("请输入要删除的元素的值: ");
scanf("%d",&e);
i = DeleteElem(L,e);
if(i)
{
printf("成功删除%d!\n",e);
}
else
{
printf("不存在元素%d!\n",e);
}
printf("线性表L为:");
ListTraverse(L,visit);

printf("请输入要取代的元素的序号  元素的新值: ");
scanf("%d %d",&n,&e);
ReplaceElem(L,n,e);
printf("线性表L为:");
ListTraverse(L,visit);

DestoryList(&L);
printf("销毁L后,按非升序重新建立n个元素的线性表L,请输入元素的个数n(n>2): ");
scanf("%d",&n);
CreatDescend(&L,n);
printf("依次输出L的元素: ");
ListTraverse(L,visit);
InsertDescend(L,10);	//按非升序插入元素10
printf("按非升序插入元素10后,线性表L为: ");
ListTraverse(L,visit);

printf("请输入要删除的元素的值: ");
scanf("%d",&e);
i = DeleteElem(L,e);
if(i)
{
printf("成功删除%d!\n",e);
}
else
{
printf("不存在元素%d\n",e);
}
printf("线性表L为: ");
ListTraverse(L,visit);

DeleteFirst(L,&e);
DeleteTail(L,&d);
printf("删除表头元素%d和表尾元素%d后,线性表L为: ",e,d);
ListTraverse(L,visit);

return 0;
}

5、运行截图:

再次感谢您的阅读!谢谢你!

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