数据结构 线性表之单链表

链表中通常都是包含两部分,一个数据域,一个指针域。前者用于存储所需要的各种数据,后者用于存储后继结点的地址。通常有一个头指针指向链表的头结点,然后头结点的指针域指向第一个结点,最后一个结点的指针域为NULL,表示后面没有了。相比于顺序表,链表的每个结点数据所占的内存可以分布在计算机内存的各个角落,需要时动态分配。

逆序创建单链表

void CreateList_L(LinkList &L, int a[], int n)

创建单链表时,首先定义链表这一数据结构,然后再定义单链表变量。其实再定义变量时链表就已经建好了,而CreateList_L函数的本质是对这个链表赋值。即先把想存到单链表里的数据存储到数组里,然后再转存到链表里。要先定义一个指向新建立结点的指针,然后通过循环对这个结点赋值,再将L头指针指向这个新建立的结点。头插法,即把每一个新结点都插入到第一个结点之前。

求链表的长度

int ListLength_L(LinkList L)

定义一个指向结点的指针,先让它指向头结点,然后往后遍历,同时k加一。while循环遍历时限制条件是while(p);确保p指向最后一个结点时也能计数。利用指针遍历链表时指针p不能是p++,而要使p=p->next;!!!

查找元素 返回其地址

LNode *LocateElem_L(LinkList L, int e)

同样是要定义一个指针来遍历链表,while循环的限制条件是while(p&&p->next!=e) 最后返回p指针。如果没有这个元素则p==NULL;

插入节点操作

void  ListInsert_L(LinkList &L, LNode *p, LNode *s)

再L为头指针的链表中,将结点s插入到结点p之前。首先判断p是否为头结点,若不是则创建一个指针q遍历,while(q->next!=p) 当跳出这个循环时q指向p的前驱结点,此时再让新建结点s指向p,然后让q指向结点s.

删除结点

int ListDelete_L(LinkList &L, LNode *p)

定义指针q用于遍历链表,然后判断p是否是头结点,如果是则直接改变头结点,L=L->next;如果不是,则用q遍历,直到q指向p的前驱结点,然后改变q的指针域。q->next=p->next; 将结点p的值赋给e,最后删除结点p。

写在最后

链表类似与顺序表但有所不同。首先,链表无法利用下标进行索引,所以如果要进行遍历的话要定义指针p,然后让指针p=p->next;注意,不能直接p++!!!然后是关于函数的形参部分,创建,插入,删除等操作要改变链表本身,所以定义函数时形参里要用LinkList &L; 求链表长度,查找元素等操作都不需要改变链表本身,所以函数的形参里用LinkList L;

上述操作的代码如下:

#include<stdio.h>

typedef struct LNode {
	int data;
	struct LNode *next;
}LNode,*LinkList;

/************************************************************************************
逆序创建单链表,即每个新结点都插在最前面                      创建
************************************************************************************/
void CreateList_L(LinkList &L, int a[], int n)
{
	//数组a[n]中存有链表需要的数据元素,逆序创建单链表L
	int i;
	LNode *s;   //s为指向新建立的结点的指针
	L = NULL;
	for (i = n - 1; i >= 0; i--)
	{
		s = new LNode;   //生成新结点
		s->data = a[i];   //给新结点赋值
		s->next = L;     
		L = s;           //将新结点插入在第一个节点之前
	}
}

/*************************************************************************************
求单链表的长度                                 求长度
**************************************************************************************/
int ListLength_L(LinkList L)
{
	//L为头指针 函数返回L所指链表的长度
	LNode *p=L;
	int k = 0;
	while (p)
	{
		k++;
		p = p->next;
	}
	return k;
}

/*****************************************************************************************
查找元素操作 返回第一个与e相等的元素在单链表中的位置             查找
******************************************************************************************/
LNode *LocateElem_L(LinkList L, int e)
{
	//由于要返回位置,所以直接返回一个指向目标数据的指针
	LNode *p = L;
	while (p&&p->data != e)
		p = p->next;
	return p;
}

/*******************************************************************************************
插入结点操作                                         插入                                                               
********************************************************************************************/
void  ListInsert_L(LinkList &L, LNode *p, LNode *s)   //此处&L一定不能省略!!!!!
{
	//指针p指向L为头指针的链表中某个结点,将s结点插入到p结点之前
	if (p == L)
	{
		s->next = L;
		L = s;
	}
	else
	{
		LNode *q = L;
		while (q->next!=p)
			q = q->next;          //当跳出while循环时,q指针已经指向p结点的前驱结点的位置
		q->next = s;
		s->next = p;
	}
}

/*********************************************************************************************
删除结点的操作  删除p所指的结点,并用e返回其值             删除
**********************************************************************************************/
int ListDelete_L(LinkList &L, LNode *p)
{
	int e;
	LNode *q;        //用于遍历链表
	if (p == L)
		L = L->next;
	else
	{
		q = L;
		while (q->next != p)
			q = q->next;    //跳出循环时q指向目标结点的前驱结点
		q->next = p->next;
	}
	e = p->data;
	delete p;
	return e;
}

/*********************************************************************************************
                                                 主函数
**********************************************************************************************/
void main()
{
	int a[10] = { 1,2,3,4,5,6,7,8,9,10 };
	int length;
	LNode *p;
	LinkList L;
	CreateList_L(L, a, 10);
	printf("新建立的单链表:");
	for (p = L; p != NULL; p = p->next)
		printf("%d ", p->data);
	printf("\n");
	length = ListLength_L(L);
	printf("该链表的长度为%d.", length);
	printf("\n");
	printf("在链表中查找数据6:");
	if (LocateElem_L(L, 6))
		printf("存在目标元素,已确定其地址,数值为%d.", LocateElem_L(L, 6)->data);
	else
		printf("目标元素不存在");
	printf("\n");
	LNode *s,*n=L;
	s = new LNode;
	s->data = 12;
	printf("新建结点s,数据域存储12,插入到链表第一个结点之前,插入后的链表为:");
	ListInsert_L(L, n, s);
	for (p = L; p != NULL; p = p->next)
		printf("%d ", p->data);
	printf("\n");
	printf("删除链表的第一个元素,返回值为%d,删除后链表为:", ListDelete_L(L,L));
	for (p = L; p != NULL; p = p->next)
		printf("%d ", p->data);
}

程序运行结果如下:

本笔记所依据的教材为严薇敏版的《数据结构及应用算法教程》

所有代码在Visual Studio 2017上均可正常运行

如有错误欢迎指出

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值