链式表示的线性表之一——单链表1

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/baidu_36669549/article/details/81222978

所谓线性表的链式存储,就是采用一组任意的存储单元存放线性表的元素。这组存储单元可以是连续的,也可以是不连续的。为了表示每个元素ai与其直接后继ai+1的逻辑关系,除了存储元素本身的信息外,还需要存储一个指示其直接后继元素的信息(直接后继元素的地址)。这两部分构成的存储结构称为结点(node)。即结点包括两个域:数据域和指针域。结点结构如图所示。

通过指针域将线性表中n个结点元素按照逻辑顺序链在一起就构成链链表。

一般情况下,我们只关心链表中结点的逻辑顺序,而不关心它的实际存储位置。通常用箭头表示指针,把链表表示成通过箭头链接起来的序列。线性表(Kang,Geng,Guan,Chen,Zhou,Hua,Feng)如图所示。

为了操作上的方便,在单链表的第一个结点之前增加一个结点,称之为头结点。头结点的数据域可以存放如线性表的长度等信息,头结点的指针域存放第一个元素结点的地址信息,使其指向第一个元素结点。带头结点的单链表如图所示。

若带头结点的单链表为空链表,则头结点的指针域为“空”,如图所示。

【存储结构】

/*02_01——存储结构*/
typedef struct Node
{
	DataType data;
	struct Node *next;
}ListNode, *LinkList;/*ListNode是链表的结点类型,LinkList是指向链表结点的指针类型*/

【基本运算】
【初始化单链表】

/*02_01——初始化单链表*/
void InitList(LinkList *head)
{
	if ((*head=(LinkList)malloc(sizeof(ListNode)))==NULL)
	{
		/*02_01为头结点分配一个存储单元*/
		exit(-1);
	}
	(*head)->next = NULL;/*02_01将单链表的头结点指针域置为空 */

}

【判断单链表是否为空】

/*02_02判断单链表是否为空*/
int ListEmpty(LinkList head)
{
	if (head->next==NULL)/*02_02如果单链表头结点的指针域为空*/
	{
		return 1;        /*02_02返回1*/
	}
	else
	{
		
		return 0;        /*02_02返回1*/
	}
}

【按照序号查找】

/*02_03按照序号查找*/
ListNode *Get(LinkList head, int i)
/*02_03按照序号查找单链表中第i个结点,查找成功返回该结点的指针表示成功;否则返回NULL表示失败*/
{
	ListNode *p;
	int j;
	if (ListEmpty(head))
	{
		return NULL;
	}
	if (i<1)
	{
		return NULL;
	}
	j = 0;
	p = head;
	while (p->next!=NULL&&j<i)
	{
		p = p->next;
		j++;

	}
	if (j==i)
	{
		return p;

	}
	else
	{
		return NULL;
	}

}

【查找元素值为e的结点】


/*02_04查找元素值为e的结点的元素,若查找成功则返回对应元素的结点指针,否则返回NULL表示失败*/
ListNode *LocateElem(LinkList head, DataType e)
{
	ListNode *p;
	p = head->next;
	while (p)
	{
		if (p->data!=e)
		{
			p = p->next;
		}
		else
		{
			break;
		}
	}
	return p;
}

【确定元素所在单链表中的序号】


/*02_05定位操作,确定元素所在单链表中的序号*/
/*02_05从头指针出发依次访问每个结点,并将结点的值与e比较,如果相等,则返回该结点序号表示成功*/
/*02_05如果没有与e相等的元素则返回0表示失败*/

int LocatePos(LinkList head, DataType e)
{
	ListNode *p;
	int i;
	if (ListEmpty(head))/*02_05在查找第i个元素之前,判断链表是否为空*/
	{
		return 0;
	}
	p = head->next;    /*02_05指针指向第一个结点*/
	i = 1;
	while (p)
	{
		if (p->data==e) /*02_05找到与e相等的元素*/
		{
			return i;   /*02_05返回该序号*/
		} 
		else
		{
			p = p->next;
			i++;
		}
	}
	if (!p)       /*02_05如果没有找到与e相等的元素*/
	{
		return 0; /*返回0*/
	}
}

【在第i个位置插入元素e】

先来看看如何在单链表中插入一个节点。假设存储元素e的结点为p,要将p指向的结点插入到pre和pre->head之间,无需移动结点元素,只需要改变p和pre指针指向即可。先把*p变成*pre的直接后继结点,如图所示,代码如下:

p->next=pre->next;
pre->next=p;

注意:
插入结点的两行代码不能颠倒顺序。如果先进行pre->next=p;后进行p->next=pre->next;操作,则第一条代码就会被覆盖掉pre->next的地址,pre->next的地址就会变成p的地址,这样pre->next就相当与上一级断开了链接。如图


在单链表的第i个位置插入一个新元素e的步骤如下:

step1.在链表中找到其直接前驱结点,即第i-1个结点,并由指针pre指向该结点,如图所示:


step2.申请一个新结点空间,由p指向该结点,将值e赋值给p指向结点的数据域。

step3.修改*p和*pre结点的指针域,如图所示

/*02_06在第i个位置插入元素e*/

int InsertList(LinkList head, int i, DataType e)
/*02_06在单链表中的第i个位置插入一个结点,结点的元素值为e。插入成功返回1,失败返回0.*/
{
	ListNode *pre, *p;/*02_06定义第i个元素的前驱结点指向pre,指针p指向新生成的结点*/
	int j;
	pre = head;/*02_06指针p指向头结点*/
	j = 0;
	while (pre->next != NULL&&j < i - 1)
		/*02_06找到第i-1个结点,即第i个结点的前驱结点*/
	{
		pre = pre->next;
		j++;
	}
	if (j!=i-1)/*02_06如果没有找到说明插入位置错误*/
	{
		cout << "02_06插入位置错误!" << endl;
		return 0;
	}
	/*02_06新生成一个结点,并将e赋值给该结点的数据域*/
	if ((p=(ListNode*)malloc(sizeof(ListNode)))==NULL)
	{
		exit(-1);
	}
	p->data = e;
	/*02_06插入结点操作*/
	p->next = pre->next;
	pre->next = p;
	return 1;

}

【删除第i个结点】

先来看看如何删除链表的第i个结点。假设p指向第i个结点,要将*p结点删除,只需将它的直接前驱结点的指针绕过,使其直接指向它的直接后继结点即可。如图所示:

删除第i个结点的步骤如下:

step1.找到第i个结点的直接前驱结点,即第i-1个结点,并用pre指向该结点,p指向其直接后继结点,即第i个结点,如图所示

step2.将*p结点的数据域赋值给e;

step3.删除第i个结点,并释放*p结点的内存空间。过如图

/*02_07删除第i个结点*/

int DeleteList(LinkList head, int i, DataType *e)
/*02_07删除单链表中的第i个结点;删除成功返回1,失败返回0。*/
{
	ListNode *pre, *p;
	int j;
	pre = head;
	j = 0;
	while (pre->next!=NULL&&pre->next->next!=NULL&&j<i-1)
	/*02_07判断是否找到前驱结点*/
	{
		pre = pre->next;
		j++;

	}
	if (j!=i-1)/*02_07如果没有找到要删除的节点位置,说明删除有误*/
	{
		cout << "02_07删除位置有误" << endl;
		return 0;
	}
	/*02_07指针p指向单链表中的第i个结点,并将该结点的数据域赋值给e*/
	p = pre->next;
	*e = p->data;
	/*02_07将前驱结点的指针域指向要删除结点的下一个结点,也就是将p指向的结点与单链表断开*/
	pre->next = p->next;
	free(p); /*02_07释放p指向的结点*/
	return 1;

}

【求表长的操作】

/*02_08求表长的操作*/
int ListLength(LinkList head)
{
	ListNode *p;
	int count = 0;
	p = head;
	while (p->next!=NULL)
	{
		p = p->next;
		count++;

	}
	return count;
}

【销毁链表操作】


/*02_09销毁链表操作*/

void DestoryList(LinkList head)
{
	ListNode *p, *q;
	p = head;
	while (p!=NULL)
	{
		q = p;
		p = p->next;
		free(q);
	}
}

猜你喜欢

转载自blog.csdn.net/baidu_36669549/article/details/81222978