算法与数据结构 基础篇 链式存储结构

算法与数据结构

链式存储结构

链式表的定义

链表是一种物理存储单元上非连续、非顺序的存储结构,数据元素的逻辑顺序是通过链表中的指针链接次序实现的。链表由一系列结点(链表中每一个元素称为结点)组成,结点可以在运行时动态生成。每个结点包括两个部分:一个是存储数据元素的数据域,另一个是存储下一个结点地址的指针域。 相比于线性表顺序结构,链表比较方便插入和删除操作。
链表并不像数组那样地址是连续的,而是分散的,但用指针将每一个地址联系起来,构成一条链的形状。 逻辑上相邻的元素不要求在物理上也相邻。

推荐阅读博文:https://blog.csdn.net/wang13342322203/article/details/80834390

链中的每一个结点由数据元素+指针组成。
数据元素就是该结点所存储的元素,指针指示后续存储位置

代码实现

在链表中应具有如下基本操作

操作函数作用
int Length(List L)求表长,返回线性表L的长度
FindKth(int K,List L)按序号查找,返回链表中的第K个元素
Find(ElementType X,List L)按值查找元素,返回链表中第一个为X的元素的结点
Insert(ElementType X,int i,List L)指定位序i前插入一个新元素X
Delete(int i,List L)删除元素 ,删除第i个元素
单结点的定义
typedef int DataType;
typedef int ElementType;

typedef struct LNode{
	DataType data;  // 数据元素的类型  
	struct LNode *Next;   // 指示结点地址的指针 
};
typedef LNode *List;
求表长
//求链的长度 
int Length(List L){
	List p=L;
	int cnt = 0;
	while(p){
		p=p->Next;
		cnt++;
	}
	return cnt;
}

查找元素
按序号进行查找
// 按序号查找元素
ElementType FindKth(int K, List L){
	List p=L;
	int cnt =1; //从第1位开始查找 
	while(p!=NULL && cnt < K){
		p=p->Next;
		cnt++;
	}
	if(cnt==K)
		return p->data; // 找到第K个,返回数据 
	else
		return -1;   // 未找到,说明K>链表长度 
}
按值查找
// 按值查找 
LNode *Find(ElementType X,List L){
	List p=L;
	while(p!=NULL && p->data!=X){
		p=p->Next;
	}
	if(p)
		return p;
	else
		return NULL;
}
插入

在链表的第i-1(1<=i<=n+1)个结点后插入值为X的新结点
步骤:

  1. 生成一个数据域为x的新节点tmp
  2. 首先找到ai-1的存储位置p
  3. 插入新结点: 1 结点ai-1的指针域指向新节点 2 新结点的指针与指向结点ai
  4. 在这里插入图片描述
无头结点插入

List InsertNoHeadNode(ElementType X,int i,List L){
	List p,tmp;
	tmp=(List) malloc(sizeof(List)); // 申请、填装结点
	tmp->data=X;
	if(i==1){   // 如果是在表头插入,则直接将指针指向表头 
		tmp->Next = L;
		return tmp; //返回表头指针 
	}
	else{
		int cnt=1;
		p=L;
		while(p && cnt<i-1){ // 查找位置i-1的结点 
			p=p->Next;
			cnt++;
		}
		if(p==NULL || cnt!=i-1){  // 第i-1个不存在,不能插入 
			printf("参数i错");
			free(tmp);
			return NULL;
		}else{
			tmp->Next = p->Next; // 新节点插入到第i-1个结点的后面 
			p->Next=tmp;
			return L;
		}
	}
}
有头结点插入

头结点: 在单链表中的第一个结点之前人为的为他附设一个结点
在这里插入图片描述


bool InsertWithHeadNode(ElementType X, int i,List L){
	List p, tmp;   // p指向表头 tmp临时结点 
	int cnt=0;
	p=L;
	while(p && cnt<i-1){  // 查找位置i-1的结点 
		p=p->Next;
		cnt++;
	}
	if(p==NULL || cnt!=i-1){  // 所找的结点不在L中 
		printf("插入位置参数错误\n");
		return false;
	}
	else{
		tmp=(List)malloc(sizeof(struct LNode));  // 申请、填装结点 
		tmp->data=X;
		tmp->Next=p->Next; // 新结点插入在第i-1个结点的后面 
		p->Next=tmp;
		return true;
	}
}

删除

删除链表的第i个位置上的结点
步骤:

  1. 先找到链表中第i-1个结点,指针p指向该节点
  2. 再用指针s指向要被删除的结点(p的下一个结点)
  3. 然后修改指针,删除s所指结点
  4. 最后释放s所指结点的空间

在这里插入图片描述

// 删除结点(带头节点)
bool Delete(int i,List L){
	
	List p,s;
	int cnt=0;
	p=L;
	while(p && cnt<i-1){
		p=p->Next;
		cnt++;
	}
	if (p==NULL || cnt!=i-1){
		printf("插入位置参数错误\n");
		return false;
	}
	else{
		s=p->Next;
		p->Next = s->Next;
		free(s);
		return true;
	}
} 
给定两个单链表,编写算法找出两个链表的公共结点

/*给定两个单链表,编写算法找出两个链表的公共结点*/
/*
    算法思想:两个链表有公共结点的话,那么从第一个公共结点开始,后面的结点都是相同的,不可
    能出现分叉。又由于两个链表的长度不一定一样,故不能同时遍历两个链表。
    可以先得到两个链表的长度l1,l2,设l1-l2=k,那么在教长的链表上遍历k个结点,在同步遍历两个链
    表,保证两个链表同时到达最后一个节点,这样也就保证了能够同时到达第一个公共结点。
*/
List SearchFirstCommon(List x1, List x2)
{
	List L1=x1, L2=x2;
    int len1 = Length(L1), len2 = Length(L2);    //获取两个线性表的长度
    List longList, shortList;        //用于指向教长,较短链表的第一个结点
    int dist;
    if (len1 > len2)
    {
        longList = L1->next;
        shortList = L2->next;
        dist = len1 - len2;
    }
    else
    {
        longList = L2->next;
        shortList = L1->next;
        dist = len2 - len1;
    }
    while (dist--)
    {
        longList = longList->next;
    }
    while (longList!=NULL)
    {
        if (longList == shortList)    //找到公共结点,返回
            return longList;
        else
        {
            longList = longList->next;
            shortList = shortList->next;
        }
    }
    return NULL;    //没有公共结点
}

完整代码

#include <iostream>
#include <stdlib.h>
using namespace std;
typedef int DataType;
typedef int ElementType;

typedef struct LNode{
	DataType data;  // 数据元素的类型  
	struct LNode *Next;   // 指示结点地址的指针 
};
typedef LNode *List;

//求链的长度 
int Length(List L){
	List p=L;
	int cnt = 0;
	while(p){
		p=p->Next;
		cnt++;
	}
	return cnt;
}

// 按序号查找元素
ElementType FindKth(int K, List L){
	List p=L;
	int cnt =1; //从第1位开始查找 
	while(p!=NULL && cnt < K){
		p=p->Next;
		cnt++;
	}
	if(cnt==K)
		return p->data; // 找到第K个,返回数据 
	else
		return -1;   // 未找到,说明K>链表长度 
}

// 按值查找 
LNode *Find(ElementType X,List L){
	List p=L;
	while(p!=NULL && p->data!=X){
		p=p->Next;
	}
	if(p)
		return p;
	else
		return NULL;
}

List InsertNoHeadNode(ElementType X,int i,List L){
	List p,tmp;
	tmp=(List) malloc(sizeof(List)); // 申请、填装结点
	tmp->data=X;
	if(i==1){   // 如果是在表头插入,则直接将指针指向表头 
		tmp->Next = L;
		return tmp; //返回表头指针 
	}
	else{
		int cnt=1;
		p=L;
		while(p && cnt<i-1){ // 查找位置i-1的结点 
			p=p->Next;
			cnt++;
		}
		if(p==NULL || cnt!=i-1){  // 第i-1个不存在,不能插入 
			printf("参数i错");
			free(tmp);
			return NULL;
		}else{
			tmp->Next = p->Next; // 新节点插入到第i-1个结点的后面 
			p->Next=tmp;
			return L;
		}
	}
}

bool InsertWithHeadNode(ElementType X, int i,List L){
	List p, tmp;   // p指向表头 tmp临时结点 
	int cnt=0;
	p=L;
	while(p && cnt<i-1){  // 查找位置i-1的结点 
		p=p->Next;
		cnt++;
	}
	if(p==NULL || cnt!=i-1){  // 所找的结点不在L中 
		printf("插入位置参数错误\n");
		return false;
	}
	else{
		tmp=(List)malloc(sizeof(struct LNode));  // 申请、填装结点 
		tmp->data=X;
		tmp->Next=p->Next; // 新结点插入在第i-1个结点的后面 
		p->Next=tmp;
		return true;
	}
}

// 删除结点(带头节点)
bool Delete(int i,List L){
	
	List p,s;
	int cnt=0;
	p=L;
	while(p && cnt<i-1){
		p=p->Next;
		cnt++;
	}
	if (p==NULL || cnt!=i-1){
		printf("插入位置参数错误\n");
		return false;
	}
	else{
		s=p->Next;
		p->Next = s->Next;
		free(s);
		return true;
	}
} 

/*给定两个单链表,编写算法找出两个链表的公共结点*/
/*
    算法思想:两个链表有公共结点的话,那么从第一个公共结点开始,后面的结点都是相同的,不可
    能出现分叉。又由于两个链表的长度不一定一样,故不能同时遍历两个链表。
    可以先得到两个链表的长度l1,l2,设l1-l2=k,那么在教长的链表上遍历k个结点,在同步遍历两个链
    表,保证两个链表同时到达最后一个节点,这样也就保证了能够同时到达第一个公共结点。
*/
List SearchFirstCommon(List x1, List x2)
{
	List L1=x1, L2=x2;
    int len1 = Length(L1), len2 = Length(L2);    //获取两个线性表的长度
    List longList, shortList;        //用于指向教长,较短链表的第一个结点
    int dist;
    if (len1 > len2)
    {
        longList = L1->next;
        shortList = L2->next;
        dist = len1 - len2;
    }
    else
    {
        longList = L2->next;
        shortList = L1->next;
        dist = len2 - len1;
    }
    while (dist--)
    {
        longList = longList->next;
    }
    while (longList!=NULL)
    {
        if (longList == shortList)    //找到公共结点,返回
            return longList;
        else
        {
            longList = longList->next;
            shortList = shortList->next;
        }
    }
    return NULL;    //没有公共结点
}

int main() {
	
	return 0;
}
  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值