【数据结构与算法】线性表的链式表示和实现,超详细【C语言版】

链式存储结构

结点在存储器中的位置是任意的,即逻辑上相邻的数据元素在物理上不一定相邻

线性表的链式表示又称为非顺序映像或链式映像。

在这里插入图片描述

与链式存储有关的术语

1、结点:数据元素的存储映像。由数据域和指针域两部分组成

2、链表: n 个结点由指针链组成一个链表。它是线性表的链式存储映像,称为线性表的链式存储结构

头指针、头结点和首元结点

在这里插入图片描述

头指针 是指向链表中第一个结点的指针

首元结点 是指链表中存储第一个数据元素a1的结点

头结点 是在链表的首元结点之前附设的一个结点;数据域内只放空表标志和表长等信息

讨论

有头结点时,当头结点的指针域为空时表示空表

1. 如何表示空表?

在这里插入图片描述

2. 在链表中设置头结点有什么好处?

⒈便于首元结点的处理 首元结点的地址保存在头结点的指针域中,所以在链表的第一个位置上的操作和其它位置一致,无须进行特殊处理;

⒉便于空表和非空表的统一处理
无论链表是否为空,头指针都是指向头结点的非空指针,因此空表和非空表的处理也就统一了。

3. 头结点的数据域内装的是什么?

头结点的数据域可以为空,也可存放线性表长度等附加信息,但此结点不能计入链表长度值。

在这里插入图片描述

链表(链式存储结构)的特点

在这里插入图片描述

链表的优缺点

优点

在这里插入图片描述

缺点

在这里插入图片描述

2.5.1 单链表的定义和实现

非空表
在这里插入图片描述
空表
在这里插入图片描述

  1. 单链表是由表头唯一确定,因此单链表可以用头指针的名字来命名
  2. 若头指针名是L,则把链表称为表L

单链表的存储结构定义

在这里插入图片描述

指针变量和结点变量

  • 指针变量p:表示结点地址

  • 结点变量*p:表示一个结点

在这里插入图片描述

2.5.2 单链表基本操作的实现

在这里插入图片描述

1、初始化

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

2、取值

在这里插入图片描述

思考:顺序表里如何找到第i个元素?

链表的查找:要从链表的头指针出发,顺着链域next逐个结点往下搜索,直至搜索到第i个结点为止。因此,链表不是随机存取结构

在这里插入图片描述

在这里插入图片描述

3、查找

在这里插入图片描述

算法描述

在这里插入图片描述
在这里插入图片描述

4、插入

在这里插入图片描述

算法步骤

在这里插入图片描述

算法描述

在这里插入图片描述

5、删除

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

算法步骤

在这里插入图片描述

算法描述

在这里插入图片描述

链表的运算时间效率分析

1. 查找:

因线性链表只能顺序存取,即在查找时要从头指针找起,查找的时间复杂度为 O(n)。

2. 插入和删除:

因线性链表不需要移动元素,只要修改指针,一般情况下时间复杂度为 O(1)。

但是,如果要在单链表中进行前插或删除操作,由于要从头查找前驱结点,所耗时间复杂度为 O(n) 。

单链表的建立(前插法)

单链表的建立(前插法)

在这里插入图片描述

在这里插入图片描述

算法描述

在这里插入图片描述

单链表的建立(尾插法)

单链表的建立(尾插法)

在这里插入图片描述

算法描述

在这里插入图片描述

单链表基本操作的代码实现 [C语言]

总功能代码

#include<stdio.h>
#define OK 1 
#define ERROR 0 
#define OVERFLOW -2
#define  MAXSIZE 100     //最大长度

// 定义参数类型
typedef int Status;
typedef int ElemType;

// 定义线性链表存储结构
typedef struct LNode{
    
    
     ElemType   data;       //数据域
     struct LNode  *next;   //指针域
}LNode,*LinkList;
// *LinkList为Lnode类型的指针

//初始化(构造一个空表 )
Status InitList_L(LinkList &L)
{
    
    
	L = new LNode;
    L->next = NULL;
    return OK;
}

//销毁
Status DestroyList_L(LinkList &L){
    
    
	 // 定义指针变量
    LinkList p;
       while(L)
        {
    
    
            p=L;  
            L=L->next;
            delete p;  
        }
     return OK;
 }

//清空
Status ClearList(LinkList & L){
    
    
  // 将L重置为空表 
   LinkList p,q;
   p=L->next;   //p指向第一个结点
   while(p)       //没到表尾 
      {
    
      q=p->next; delete p;     p=q;   }
   L->next=NULL;   //头结点指针域为空 
   return OK;
 }

//求表长
int  ListLength_L(LinkList L){
    
    
//返回L中数据元素个数
    LinkList p;
	int i;
    p=L->next;  //p指向第一个结点
     i=0;             
     while(p){
    
    //遍历单链表,统计结点数
           i++;
           p=p->next;    } 
    return i;                             
 }

//判断表是否为空
int ListEmpty(LinkList L){
    
     
//若L为空表,则返回1,否则返回0 
   if(L->next)   //非空 
     return 0;
   else
     return 1;
 }

//取值(根据位置i获取相应位置数据元素的内容)
//获取线性表L中的某个数据元素的内容
Status GetElem_L(LinkList L,int i,ElemType &e){
    
     
	LinkList p;
	int j;
    p=L->next;j=1; //初始化
     while(p&&j<i){
    
    	//向后扫描,直到p指向第i个元素或p为空 
       p=p->next; ++j; 
     } 
     if(!p || j>i)return ERROR; //第i个元素不存在 
     e=p->data; //取第i个元素 
     return OK; 
}//GetElem_L 


//查找(返回查找元素地址)
//在线性表L中查找值为e的数据元素
LNode *LocateElem_L(LinkList L, ElemType e)
{
    
    
    LinkList p;
    p = L->next;
    while (p && p->data != e)
    {
    
    
        p = p->next;
        // 返回 L 值为 e 的数据元素的地址,查找失败返回 NULL
        return p;
    }
	return 0;
}

// 查找(返回查找元素序号)
//在线性表L中查找值为e的数据元素
int LocateElem(LinkList L, ElemType e)
{
    
    
    LinkList p;
    int j = 1;
    p = L->next;
    while (p && p->data != e)
    {
    
    
        p = p->next;
        j++;
    }
    if (p)
    {
    
    
        return j;
    }
    else
    {
    
    
        return 0;
    }
}

//插入
Status ListInsert(LinkList &L, int i, ElemType e)
{
    
    
    LinkList p = L, s;
    int j = 0;
    // 寻找第 i-1 个结点
    while (p && j < i - 1)
    {
    
    
        p = p->next;
        ++j;
    }
    // i 大于表长 +1 或者小于 1
    if (!p || j > i - 1)
    {
    
    
        return ERROR;
    }
    // 生成新结点 s
    s = new LNode;
    // 将结点 s 的数据域置为 e
    s->data = e;
    // 将结点 s 插入 L 中
    s->next = p->next;
    p->next = s;
    return OK;
}//ListInsert_L 

//删除
Status ListDelete_L(LinkList &L,int i,ElemType &e){
    
    
	LinkList p,q;
	int j;
    p=L;j=0; 
    while(p->next &&j<i-1){
    
    //寻找第i个结点,并令p指向其前驱 
        p=p->next; ++j; 
    } 
    if(!(p->next)||j>i-1) return ERROR; //删除位置不合理 
    q=p->next; //临时保存被删结点的地址以备释放 
    p->next=q->next; 	//改变删除结点前驱结点的指针域 
    e=q->data; 	//保存删除结点的数据域 
    delete q; 	//释放删除结点的空间 
 return OK; 
}//ListDelete_L 

//单链表的建立(前插法)
void CreateList_F(LinkList &L,int n){
    
     
	int i;
	LinkList p;
	L=new LNode; 
	L->next=NULL; //先建立一个带头结点的单链表 
	for(i=n;i>0;--i){
    
     
	p=new LNode; //生成新结点 
	//cin>>p->data; //输入元素值 
	scanf("%d",&p->data);
	p->next=L->next;L->next=p; 	//插入到表头 
     } 
}//CreateList_F 

// // 单链表建立(尾插法)
void CreateList_L(LinkList &L, int n)
{
    
    
    LinkList p, r;
    // 正位序输入n 个元素的值,建立带表头结点的单链表L
    L = new LNode;
    L->next = NULL;
    // 尾指针r指向头结点
    r = L;
    printf("please enter element:");
    for (int i = 0; i < n; ++i)
    {
    
    
        p = new LNode;
        scanf("%d", &p->data);
        // 插入到表尾
        p->next = NULL;
        r->next = p;
        // r指向新的尾结点
        r = p;
    }
}

//输出
void printList(LinkList L){
    
    
	LinkList p;
	p = L->next;
		while(p){
    
    
			printf("%d  ",p->data);
			p=p->next;
		}
	printf("\n");
}

void main(){
    
    
	LinkList L;

	ElemType N;

	//初始化
	InitList_L(L);
	
	//单链表的建立(前插法)
	//CreateList_F(L,4);
	//printList(L);

	// 单链表建立(尾插法)
	CreateList_L(L,4);
	//printList(L);
	
	// 插入
	//ListInsert(L,2,3);
	//printList(L);

	//删除
	ListDelete_L(L,2,N);
	printList(L);


	//printf("%d\n",m);
}

前插

void main(){
    
    
	LinkList L;

	//初始化
	InitList_L(L);
	
	//单链表的建立(前插法)
	CreateList_F(L,4);
	printList(L);
}

在这里插入图片描述

尾插

void main(){
    
    
	LinkList L;

	//初始化
	InitList_L(L);
	
	//单链表的建立(前插法)
	//CreateList_F(L,4);
	//printList(L);

	// 单链表建立(尾插法)
	CreateList_L(L,4);
	printList(L);
	}

插入

void main(){
    
    
	LinkList L;

	//初始化
	InitList_L(L);
	
	//单链表的建立(前插法)
	//CreateList_F(L,4);
	//printList(L);

	// 单链表建立(尾插法)
	CreateList_L(L,4);
	//printList(L);
	
	// 插入
	ListInsert(L,2,3);
	printList(L);
	}

在位置2插入数字3
在这里插入图片描述

删除

void main(){
    
    
	LinkList L;

	ElemType N;

	//初始化
	InitList_L(L);
	
	//单链表的建立(前插法)
	//CreateList_F(L,4);
	//printList(L);

	// 单链表建立(尾插法)
	CreateList_L(L,4);
	//printList(L);
	
	// 插入
	//ListInsert(L,2,3);
	//printList(L);

	//删除
	ListDelete_L(L,2,N);
	printList(L);


	//printf("%d\n",m);
}

在这里插入图片描述

取值(根据位置i获取相应位置数据元素的内容)

void main(){
    
    
	LinkList L;

	ElemType N;

	//初始化
	InitList_L(L);
	
	//单链表的建立(前插法)
	//CreateList_F(L,4);
	//printList(L);

	// 单链表建立(尾插法)
	CreateList_L(L,4);
	//printList(L);

	//取值(根据位置i获取相应位置数据元素的内容)
	GetElem_L(L,2,N);
	printf("%d\n",N);
	}

在这里插入图片描述

查找

求表长

printf("链表长度为:%d\n\n", ListLength_L(L));

在这里插入图片描述

清空、销毁链表、判断是否为空

//判断表是否为空
    ListEmpty(L);

	//清空链表
	ClearList(L);
	printf("清空链表之后,");
	printf("%d\n",ListEmpty(L));
	//销毁链表
	if(DestroyList_L(L)){
    
    
		printf("链表销毁成功!\n");
	}

在这里插入图片描述

2.5.3 循环链表

持续更新中

Guess you like

Origin blog.csdn.net/qq_45696377/article/details/120459665