数据结构 线性表的链式表示和实现 增删找查

1.单链表的定义和表示:
任意一组存储单元存储线性表的数据元素(这组存储单元可连续也可不连续)结点包含两个域:数据域(存储元素信息)和指针域(存储直接后继位置(指针或链))。
n个结点连结成一个连结成一个链表即为线性表

特点:不要求逻辑上相邻的两个元素物理上也相邻
通过“链”建立起数据元素之间的逻辑关系
插入、删除不需要移动数据元素,只需要改链
但对于访问序号为i的元素和求线性表的长度为多少就比顺序表复杂

在这里插入图片描述
线性表的链式存储实现

typedef struct LNode*List;
struct LNode{
	ElementType Data;
	List Next; 
};
struct LNode L;
List Ptrl;

1.求表长

int Length (List Ptrl){
	List p=Ptrl;//p指向表的第一个结点 
	int j=0;
	while(p){
		p=p->Next;//当前p指向的时第j个结点 
		j++;
		
	}
	return j;
	
}

查找

//查找
//(1)按序号查找:FindKth
List FindKth(int K,List Ptrl){
	List p=Ptrl;
	int i=1;
	while (p!=NULL&&i<K){
		p=p->Next;
		i++;
	}
	if(i==K)return p
	else return NULL;
	
} 
//(2)按值查找Find
List Find(ElementType X,List Ptrl){
	List p=Ptrl;
	while(p!=NULL&&p->Data!=X)
	p=p->Next;
	return p;
} 

插入
在这里插入图片描述

在这里插入图片描述

//插入
List Insert(ElementType X,int i,List Ptrl){
	List p,s;
	if(i==1){//新结点插在表头 
		s=(List)malloc(sizeof(struct LNode));
		s->Data=X;
		s->Next=Ptrl;
		return s;
	}
	//如果不是第一个则需要判断输入的i是否合法,由于还需考虑,表的长度,表是否为空之类的问题
	//直接判断要插入的位置的前面是否还有元素,如果没有,则说明这个位置错误
	//若果有,则插入
	p=FindKth(i-1,Ptrl);
	if(p==NULL){
		printf("参数错误");
		return NULL;
	} 
	
	else{
		s=(List)malloc(sizeof(struct LNode));
		s->Data=X;
		s->Next=p->Next;//只需要考虑要插入的位置前面的结点的关系,替代它的后继 
		p->Next=s;//改变它的后继 
		return Ptrl;
		
	}
}

删除
先找到链表的第i-1个结点,用p指向
再用指针s指向要被删除的结点(p的下一个结点);
然后修改指针,删除s所指结点
最后释放s结点的空间
在这里插入图片描述

 List Delete(int i,List Ptrl) {
 	List p,s;
 	if(i==1){
 		s=Ptrl;
 		if(Ptrl!=NULL)
 		Ptrl=Ptrl->Next;
 		else return NULL;//如果这个头指针是空的,后面没有结点了,删了不就都空了吗?
		free(s);
		return Ptrl; 
	 }
 }
 p=FindKth(i-1,Ptrl);
 if(p==NULL){
 	printf("第%d个结点不存在",i-1);return NULL;
 }
 else if(p->Next==NULL){
 	printf("第%d个结点不存在",i);return NULL;
 }
 else {
 	s=p->Next;
 	p->Next=s->Next;
 	free(s);
 	return Ptrl;
 }

另一种方法:数据结构书上的
先认识几个概念
首元结点:链表存储中的第一个元素
头结点:首元结点之前的特意设置的一个结点,其指针域指向首元结点,数据域可为空
头指针:第一个结点的指针,若有头结点则为头结点的指针,若没有则为首元结点的指针

头结点的作用:
增加头结点方便首元结点的处理
则对链表的第一个数据元素的操作与其他元素相同
便于空表非空表的统一处理
若没有头结点,若链表为空,则首元结点没有,则指向首元结点的头指针L为空判断条件:LNULL
若存在头结点,无论链表是否为空,头指针都是指向头结点的非空指针。
若为空表,则头指针的指针域为空
L->next
NULL

#include<iostream>
using namespace std;
#include<stdlib.h>
#define ok 1 
#define error 0
typedef int ElemType;
typedef int status;

//单链表的存储结构
typedef struct LNode{
	ElemType data;//结点的数据域 
	struct LNode *next; //结点的指针域 
}LNode,*LinkList; //定义结构体变量。这俩实际上一样都是变量
//就是*LinkList定义变量的时候 比如说指针,不用带*
LinkList p;
//单链表的初始化
status InitList(LinkList &L){
	L=new LNode;//生成新节点作为头结点,用头指针指向头结点
	L->next=NULL;
	 return ok;
} 
//单链表的取值
status GetElem(LinkList L,int i,ElemType e){
	p=L->next;int j=1;
	while (p&&j<i){
		p=p->next;
		j++;
	}
	if(!p||j>i)return error;//i值不合法,i>n或i<=0 
	e=p->data;
	return ok;
} 
LNode*LocateElem(LinkList L,ElemType e){
	p=L->next;
	while(p&&p->data!=e)
	p=p->next;
	return p;//查找成功返回值为e,查找失败p为NULL 
	
}
//插入 
status ListInsert(LinkList &L,int i,ElemType e){
	LinkList s;
	p=L;int j=0;
	while(p&&j<i-1)
	{
	p=p->next;
	j++;}
	if(!p||j>i-1)return error;//i>n+1或i<1 
	s=new LNode;
	s->data=e;
	s->next=p->next;
	p->next=s;
	return ok; 
} 
//删除
status ListDelete(LinkList &L,int i){
	LinkList q;
	p=L;//头结点 
	int j=0;
	while((j<i-1)&&p->next){
		p=p->next;j++;
		
	}
	if(!(p->next)||(j>i-1))return error;
	q=p->next;
	p->next=q->next;
	delete q;
	return ok;
} 


 int main(){
 	int a=3;
 	LinkList L;
 	InitList(L);
 	ListInsert(L,1,2);//往链表里输入数据,可以先用这个插入的函数 
 	ListInsert(L,1,a);
 	cout<<L->next->data<<endl<<L->next->next->data;
 	
 }

简单的测试
在这里插入图片描述
用前插法或后插法往链表里添加数据:
前插法就是一直在头结点之后插入,因此第一个插入的等所有数据插入完就成了最后一个。(这是我们应该考虑的)

//前插法创建单链表
 
void CreateList_H(LinkList &L,int n){
 	LinkList p;
	L=new LNode;
	L->next=NULL;//先建立一个带头结点的空链表 
	for(int i=0;i<n;i++){
		p=new LNode;
		cin>>p->data;
		p->next=L->next;L->next=p; 
	} 

} 

后插法
就是在后面插入,就跟排队一样,在链表内的顺序与插入顺序一致

//后插法创建单链表
 void CreateList_R(LinkList &L,int n){
  	LinkList p;
	L=new LNode;
	L->next=NULL;//先建立一个带头结点的空链表 
	//采用头指针的思想,弄个尾指针
	LinkList r;
	r=L;//尾指针指向头结点 
	for(int i=0;i<n;i++){
		p=new LNode;
		cin>>p->data;
		p->next=NULL;r->next=p; //将新结点*p插入尾结点之后 
		r=p;//将最后一个结点作为新的尾结点 
		
	} 
} 

前插法具体实现运行案例请点击此处数据结构 单链表头插法
后插法请点击此处尾插法

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值