数据结构-线性链表(C语言实现)

数据结构-线性链表(链式存储实现-C语言)

链式理解:
线性表的顺序存储结构的特点是逻辑上相邻的元素在物理存储(计算机内存)上也是相邻,可以计算任意一个元素的地址(原理与计算公式在顺序表实现章节),从而可以随机存取任意一个元素,但这种结构存在些弱点:在作插入和删除元素时,需要移动大量元素。链表却与之不同,链表是逻辑上相邻的元素在物理存储上不一定相邻,因而在作插入和删除元素时不需要移动大量元素,但同时也因为物理存储不相邻,所以失去了随机存取的优点。
名词介绍:
先理解几个概念:结点、头指针、头结点、首元结点
		结点:线性链表中单个元素不仅存储本身的信息还存储一个指向其直接后继的信息		     (即直接后继的存储位置,这在C中使用指针保存这个位置),这两部分信息组成在一起就是一个结点。结点中包含数据信息的部分叫数据域,包含地址信息的部分叫做指针域。
		头指针:指向整个链表开始的一个结点(这个结点可能是头结点或者首元结点)的指针,一般用L表示。
		首元结点:链表的第一个数据元素。
		头结点:在首元结点之前增加一个结点,这个结点就是头结点。
		![在这里插入图片描述](https://img-blog.csdnimg.cn/749522e5c1374a5a9c01086c445bac02.png#pic_center)

线性链表有两种结构:
		第一种:带头结点(常用)
		![在这里插入图片描述](https://img-blog.csdnimg.cn/7d5f0b0481eb40c782f55379d67957ea.png#pic_center)
		第二种:不带头结点(不常用)
		![在这里插入图片描述](https://img-blog.csdnimg.cn/437bb54601354cf1af44eeeed0794817.png#pic_center)
算法实现

首先定义线性表的单链表存储结构体

#include <stdio.h>
#include <stdlib.h>
#define TRUE 1
#define FALSE 0
#define OK 1
#define ERROR 0
#define INFEASIBLE -1
#define OVERFLOW -2
typedef int Status;
typedef char ElemType;//元素类型可以根据自己需求自定义类型,这里以char类型为例

typedef struct LNode{
	ElemType data;      //数据域
	struct LNode *next; //指针域
} LNode,*LinkList;

(备注:1.以上代码供下方的算法实现使用。2.根据自己的需求可以在下面代码实现中添加自己的一些判空处理,增加代码严谨性)

说明:以下的线性链表均带头结点的,链表简单的操作不给予实现,只记录重要的几个操作)
**一、**初始化线性链表(或单链表)

Status InitList_L(LinkList &L){//为了操作方便,使用c++中的引用操作符"&"
	L=(LinkList)malloc(sizeof(LNode));//内存中开辟一个和LNode结构体一样大小的空间,返回这个空间的首地址(头指针指向头结点)
	(*L)->next=NULL;//链表为空
	return OK;
} 

**二、**销毁线性链表(或单链表):从头结点开始遍历,依次释放每一个结点

Status DestroyList_L(LinkList L){
//	可编写自己的判空处理逻辑,使代码严谨
	LNode *p,*L1=L->next;
	while(L1){//首元结点存在,则开始遍历
		p=L1;
		L1=L1->next;
		free(p);
	}
	return OK;
}

**三、**查找单链表的第i个元素(按位置查找):因位置 i 值不同,分为三种情况:
1.如果i大于链表的元素个数,这时满足循环条件进行遍历直到p为NULL(这时j还是小于i)
2.如果i小于链表的元素个数(即i<1),这时循环条件不满足(j<i条件不满足)循环结束
3.如果1<= i <=链表元素个数(合法范围),循环进行到 j=i 时退出循环(这时p不为NULL),最终e=p->data执行,即第i个元素查找成功。

Status GetElem_L(LinkList L,int i,ElemType &e){                       
	Lnode *p=L->next;                                                               
	int j=1;                                                     
	while(p&&j<i){
		p=p->next;
		++j;
	}
	if(!p || j>i) return ERROR;
	e=p->data;
	return OK;
}

**三-1、**按值查找,返回改值元素的地址

Lnode* LocateElem_L1(LinkList L,ElemType e){
	Lnode *p=L->next;
	while(p&&p->data!=e){
		p=p->next;
	}
	return p;
}

**三-2、**按值查找、返回该值元素在链表中的位置(第几个元素,从1开始)

int LocateElem_L2(LinkList L,ElemType e){
	Lnode *p=L->next;
	int j=1;
	while(p&&p->data!=e){
		p=p->next;
		j++;
	}
	if(p) return j;
	else return 0;
}

**四、**向链表中第i个位置插入新的元素(要点:向第i个位置上插入一个元素,意味着要先找到第i个元素的前一个元素(记为pre),然后新建一个结点,使该节点的next指针等于pre->next,然后把pre的next指针指向新建的结点。)

Status ListInsert_L(LinkList L,int i,ElemType e){
	Lnode *p=L->next,*s;
	int j=0;
	while(p&&j<i-1){//找到第i元素的前一个元素
		p=p->next;
		j++;
	}
	if(!p||j>i-1)return ERROR;
	s=(LinkList)malloc(sizeof(Lnode));
	s->next=p->next;
	p->next=s;
	return OK;
} 

**五、**删除链表中第i个元素(要点:和插入的类似,先找到要删除的第i个元素的前一个元素§,然后元素p的next指针指向下一个元素的next所指向的元素(在指针指向之前先使用变量q保存下p的next所指向的结点)
然后使用free(q)释放要删除的结点即可

Status ListDelete_L(LinkList L,int i){
	int j=0;
	Lnode *p=L->next,*q;
	while(p&&j<i-1){
		p=p->next;
		j++;
	}
	if(!p||j>i-1) return ERROR;
	q=p->next;
	p->next=p->next->next;
	free(q);
	return OK;
} 

注:有关链表的操作还有许多,比如:头插法创建链表、尾插法创建链表、链表清空、计算链表长度、判断链表是否、合并两个单链表(两个非递减单链表合成为一个非递减单链表)等…
(本文仅仅是个人在学习数据结构中做的笔记,留作纪念)

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
线性链表是一种常见的数据结构,它由一系列的节点组成,每个节点包含数据和指向下一个节点的指针。下面是一个用C语言实现线性链表的代码示例: ```c #include <stdio.h> #include <stdlib.h> // 定义节点结构 typedef struct Node { int data; struct Node* next; } Node; // 创建链表 Node* createLinkedList() { Node* head = (Node*)malloc(sizeof(Node)); head->next = NULL; return head; } // 在链表末尾插入节点 void insert(Node* head, int data) { Node* newNode = (Node*)malloc(sizeof(Node)); newNode->data = data; newNode->next = NULL; Node* current = head; while (current->next != NULL) { current = current->next; } current->next = newNode; } // 在链表指定位置插入节点 void insertAt(Node* head, int data, int position) { Node* newNode = (Node*)malloc(sizeof(Node)); newNode->data = data; Node* current = head; int i = 0; while (current->next != NULL && i < position - 1) { current = current->next; i++; } newNode->next = current->next; current->next = newNode; } // 删除链表指定位置的节点 void deleteAt(Node* head, int position) { Node* current = head; int i = 0; while (current->next != NULL && i < position - 1) { current = current->next; i++; } if (current->next != NULL) { Node* temp = current->next; current->next = temp->next; free(temp); } } // 输出链表的所有节点 void display(Node* head) { Node* current = head->next; while (current != NULL) { printf("%d ", current->data); current = current->next; } printf("\n"); } int main() { Node* myList = createLinkedList(); // 插入节点 insert(myList, 1); insert(myList, 3); insert(myList, 5); insert(myList, 7); // 在指定位置插入节点 insertAt(myList, 9, 2); // 删除指定位置的节点 deleteAt(myList, 3); // 输出链表 display(myList); return 0; } ``` 以上代码实现线性链表的基本操作,包括创建链表、在链表末尾插入节点、在指定位置插入节点、删除指定位置的节点,以及输出链表的所有节点。使用这些操作可以对线性链表进行增删改查等操作。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值