2.3 线性表的链式表示

2.3.1  单链表的定义

typedef struct                   //定义 单链表结点 类型:结构体
{    
	int data;                    //数据域
	struct LNode *next;          //指针域
}LNode,*LinkList;                //LNode:强调结点    LinkList:强调链表

链表又分为 有头结点,无头结点 头指针始终指向链表第一个结点

无头结点:(无头结点 写代码麻烦 不推荐使用)

初始化:

bool InitList(LinkList &L)
{
	L = NULL;					    	//空表 无任何节点
	return true;
}

判断空表:

bool Empty(LinkList L)
{
	return (L == NULL);
}

有头结点:(带头结点 写代码方便 用过的都说好 [doge])

初始化:

bool InitList(LinkList &L)
{
	L = (LNode*)malloc(sizeof(LNode));
	if (L == NULL)				        	//内存不足 申请空间失败
		return false;	
		    					
	L->next = NULL;				        	//L指向的头节点的指针置为空 头结点的数据域(data)不存储信息 
	return true;					        //头结点后无其它结点
}

判断空表:

bool Empty(LinkList L)
{
	return (L->next==NULL);
}

求表长:

int Length(LinkList &L)
{
	int l = 0;
	LNode* p = L;
	while (p->next != NULL)
	{
		p = p->next;
		l++;
	}
	return l;
}

2.3.2 单链表基本操作的实现

 1)  按序号 插入结点(在第i个位置 插入结点)注:可插表尾

//有头结点
bool ListInsert(LinkList &L, int i, int e)		//i:第i个位置 e:结点值
{
	if (i <= 0)return false;
	LNode* p = L;					            //L指向头结点头结点是第0个结点
	int j = 0;						            //当前p指向的是第几个结点
	while (p != NULL&&j < i - 1)	            //循环找到要插入位置的前一个结点
	{
		p = p->next;
		j++;
	}
	if (p == NULL)return false;				    //超出范围(不合法)

	LNode* NewNode = (LNode*)malloc(sizeof(LNode));
	NewNode->data = e;
	NewNode->next = p->next;		            //插入顺序不能颠倒 否则导致信息缺失!!!
	p->next = NewNode;				
	return true;
}
//无头结点
bool ListInsert(LinkList &L, int i, int e)
{
	if (i <= 0)return false;        //插入到第一个结点时 与其他不同 单独讨论
	if (i == 1)
	{
		LNode* NewNode = (LNode*)malloc(sizeof(LNode));
		NewNode->data = e;
		NewNode->next = L;
		L = NewNode;
		return true;
	}

	int j = 1;						//注意!!! 此时 j(当前p 指向的结点)是从第一个结点开始
	LNode* p = L;					//p表示 指向的结点
	while (p != NULL&&j < i - 1)	//循环 找目标结点
	{
		p = p->next;
		j++;
	}
	if (p == NULL)return false;

	LNode* NewNode = (LNode*)malloc(sizeof(LNode));
	NewNode->data = e;
	NewNode->next = p->next;
	p->next = NewNode;
	return true;
}

2.1)  LNode* p(结点)后插入结点

//在结点之后插入元素e
bool InsertNextNode(LNode* p, int e)
{
	if (p == NULL)return false;
	LNode* NewNode = (LNode*)malloc(sizeof(LNode));
	if (NewNode == NULL)return false;
	NewNode->data = e;
	NewNode->next = p->next;
	p->next = NewNode;
	return true;
}

2.2)  LNode* p(结点)前插入结点

///
//时间复杂度O(n)
//在结点之前插入元素e(需要头指针LinkList &L)
bool InsertPriorNode(LinkList &L, LNode* p, int e)
{
	if (p == NULL)return false;
	LNode *t = L;
	while (t != NULL&&t->next!=p)		//(需要根据链表表头)找到目标结点的上一个结点 进行后插操作
	{
		t = t->next;
	}
	return InsertNextNode(t, e);				//后插操作
}

//
//时间复杂度O(1)
//在结点之前插入元素e(不需要头指针LinkList &L)
bool InsertPriorNode(LNode* p, int e)
{
		                            先后插
	if (p == NULL)return false;
	LNode *NewNode = (LNode*)malloc(sizeof(LNode));
	if (NewNode == NULL)return false;
	NewNode->data = e;
	NewNode->next = p->next;
	p->next = NewNode;
		                            再交换两结点数据 
	NewNode->data = p->data;
	p->data=e;
	return true;
}

3.1)  删除某位置结点

//只考虑有头结点的情况
bool ListDelete(LinkList &L,int i, int &e)
{
	int j = 0;
	LNode* p = L;

	while (p != NULL&&j < i - 1)			//找到目标结点q的 前一个结点p
	{
		p = p->next;
        j++;
	}
	if (p == NULL)return false;

    if (p->next == NULL)return false;
	LNode* q = p->next;						//目标结点
	e = q->data;							//利用e返回
	p->next = q->next;
	free(q);
}

3.2)  删除某指定结点

//只考虑有头结点的情况
//需利用头指针
//时间复杂度O(n)
bool ListDelete(LinkList &L,LNode* p,int &e)
{
	if (p == NULL)return false;
	LNode* fp = L;

	while (fp != NULL&&fp!=p->next)		//找到目标结点的 前一个结点
	{
		fp = fp->next;
	}
	if (fp == NULL)return false;

	e = p->data;
	fp->next = p->next;
	free(p);
	return true;
}
//可删除任何结点!!!!!!!
//只考虑有头结点的情况
//不需利用头指针
//时间复杂度O(1)
bool ListDelete(LNode* p)
{
	if (p == NULL)return false;

	LNode* q = p->next;				//找到p的下一个结点q偷天换日
	p->data = q->data;
	p->next = q->next;
	free(q);
	return true;
}
//不可删除最后一个结点!!!!!!!

4.1)  按位查找(返回结点)

//只考虑有头结点的情况
LNode* GetElem(LinkList &L, int i)
{
	if (i < 0)return NULL;

	int j = 0;                      //当前 p 指向的 是第几个结点
	LNode* p = L;
	while (p != NULL&&j < i)		//找到第 i 个结点
	{
		p = p->next;
		j++;
	}
	return p;
}
//将查找结点这一操作进行封装 直接使用GetNode(L,i-1)就可找到目标位置前一个结点

4.2)  按值查找(返回结点)

LNode* LocateElem(LinkList &L, int e)
{
	LNode* p = L->next;				//需从第一个结点开始查找
	while (p != NULL&&p->data != e)
	{
		p = p->next;
	}
	return p;
}

5)  尾插法建立单链表

LinkList Link_TailInsert(LinkList &L)
{
	LNode* t = L;
	int x = 0;
	while (scanf("%d", &x) != EOF)
	{
		LNode* p = (LNode*)malloc(sizeof(LNode));
		p->data = x;
		t->next = p;
		t = p;
	}
	t->next = NULL;			//表尾置为空
	return L;
}

 2.3.3  双链表

定义

typedef struct DNode
{
	int data;
	DNode* prior;
	DNode* next;
}DNode,*DLinkList;					//DNode:结点  DLinkList:(双)链表

判空

bool Empty(DLinkList& L)
{
	if (L->next == NULL)
		return false;
	else return true;
}

1)双链表初始化

bool InitDLinkList(DLinkList& L)
{
	L = (DNode*)malloc(sizeof(DNode));
	if (L == NULL)return false;

	L->prior = NULL;				//头结点的prior 永远为 NULL
	L->next = NULL;
	return true;
}

2)双链表插入

//结点p之后插入
bool InsertNextDNode(DNode* p, DNode* New)
{
	if (p == NULL || New == NULL)return false;
	New->next = p->next;
	if (p->next != NULL)			//p之后有结点
	{
		p->next->prior = New;
	}
	p->next = New;
	New->prior = p;
    return true;
}
//结点p之前插入
bool InsertPriorDNode(DNode* p, DNode* New)
{
	if (p == NULL || New == NULL)return false;
	return InsertNextDNode(p->prior, New);        //找到p的前一个结点 后插
}

3)双链表删除

//结点p之后删除
bool DeleteNextDNode(DNode*p)
{
	if (p == NULL||p->next==NULL)		//结点为空 或无后继
		return false;
	DNode*q = p->next;
	p->next = q->next;
	if (q->next != NULL)
		q->next->prior = p;
	free(q);
	return true;
}
//销毁链表
void Destroy(DLinkList&L)
{
	while (L->next != NULL)			//依次删除 头节点之后的结点
		DeleteNextDNode(L);
	free(L);
	L = NULL;
}

4)双链表遍历

//从前->后遍历
while (p != NULL)
{
	//一系列操作
	p = p->next;
}
//从后->前遍历(操作头结点)
while (p != NULL)
{
	//一系列操作
	p = p->prior;
}
//从后->前遍历(不包括头结点)
while (p->prior != NULL)
{
	//一系列操作
	p = p->prior;
}

2.3.4  循环链表

1  循环链表

 2  静态链表

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值