C/C++语言数据结构快速入门(代码解析+内容解析)链表(单链表,双链表,循环链表,静态链表)

Posted 蓝盒子bluebox

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了C/C++语言数据结构快速入门(代码解析+内容解析)链表(单链表,双链表,循环链表,静态链表)相关的知识,希望对你有一定的参考价值。

一、单链表

1、链表(链式存储)相关概念

(1)什么是单链表

(2)用代码定义一个单链表


(3)用代码定义一个单链表


头插法建立单链表的算法如下:

LinkList * GetElem(LinkList L,int i){
	LNode *s;int x;
	L = (LinkList)malloc(sizeof(LNode)); 
	L->next = NULL;
	scanf("%d",&x);
	while(x != 9999){
		s = (LNode*)malloc(sizeof(LNode));
		s->data = x;
		s->next=L->next;
		L->next=s;
		scanf("%d",&x);
	}
	return L;
}

强调一点这是一个单链表 --使用LinkList
强调这是一个结点 --使用LNode *

(4)不带头结点的单链表

(5)带头结点的单链表

(6)不带头结点VS带头结点


2、单链表的插入和删除


(1)按位序插入(带头结点)

ListInsert(&L,i,e):插入操作。在表L中的第i个位置上插入指定元素e

头结点是第0个结点(不存储数据)

a、第一种情况:i的值等于1(最好的情况)
#include<stdio.h>
typedef struct LNode{
	ElemType data;
	struct LNode *next;
}LNode, *LinkList;
//在第i个位置插入元素e(带头结点)
bool ListInsert(LinkList &L,int i,ElemType e){
	if(i < 1)
		return false;
	LNode *p; //指向p指向当前扫描的结点
	int j = 0;//当前p指向的是第几个结点
	p = L;	//L指向头结点,头结点是第0个结点(不存储数据)
	while(p != NULL && j < i - 1){	//循环找到第i-1个结点
		p = p -> next;
		j++;
	}
	if(p==NULL) //i值不合法
		return false;
	LNode *s = (LNode *)malloc(sizeof(LNode));
	s->data = e;
	s->next = p->next;
	p->next = s;	//将结点s连接到p之后 
	return true;	//插入成功 
} 

b、第二种情况:i的值等于3

c、第三种情况:i的值等于5(最坏的情况)

d、第三种情况:i的值等于6

3、按位序插入(不带头结点)

ListInsert(&L,i,e):插入操作。在表L中的第i个位置上插入指定元素e。

(1)如果i>1的时候

#include<stdio.h> 
typedef struct LNode{
	ElemType data;
	struct LNode *next;
}LNode,*LinkList;

bool ListInsert(LinkList &L,int i,ElmeType e){
	if(i < 1){
		return false;
	}
	if(i == 1){//插入第1个结点的操作与其他操作不同 
		LNode *s = (LNode *)malloc(sizeof(LNode));
		s->data = e;
		s->next=L;
		L = s;	//头指针指向新的结点 
		return true;
	}
	LNode *p; //指针p指向当前扫描的结点
	int j = 1;//当前p指向的是第几个结点 
	p = L;//p指向的是第几个结点
	while(p != NULL && j < i-1){ //循环找到第i-1个结点 
		p = p->next;
		j++;
	} 
	if(p==NULL){//i的值不合法 
		return false;
	}
	LNode *s = (LNode *)malloc(sizeof(LNode));
	s->data = e;
	s->next = p->next;
	p->next = s;
	return true;//插入成功 
	 
}

4、指定结点的后插操作

a、第一种方式

#include<stdio.h> 
typedef struct LNode{
	ElemType data;
	struct LNode *next;
}LNode,*LinkList;

bool ListInsert(LinkList &L,int i,ElmeType e){
	if(i < 1){
		return false;
	}
	LNode *p; //指针p指向当前扫描的结点
	int j = 0;//当前p指向的是第几个结点 
	p = L;//p指向的是第几个结点
	while(p != NULL && j < i-1){ //循环找到第i-1个结点 
		p = p->next;
		j++;
	} 
	if(p==NULL){//i的值不合法 
		return false;
	}
	LNode *s = (LNode *)malloc(sizeof(LNode));
	s->data = e;
	s->next = p->next;
	p->next = s;
	return true;//插入成功 
}

b、第二种方式

typedef struct LNode{
	ElemType data;
	struct LNode *next;
}LNode ,*LinkList; 
//后插操作:在p结点之后后插元素e
bool InsertNextNode(LNode *p,ElemType e) {
	if( p == NULL ){
		return false;
	}
	LNode *s = (LNode *)malloc(sizeof(LNode));
	if(s == NULL){	//内存分配失败  某些情况下有可能分配失败(如内存不足) 
		return false;
	}
	s->data = e;	//用结点s保存元素e 
	s->next = p->next;
	p->next = s;	//将结点s连接到p之后 
	return true;
}

5、指定结点的前插操作

a、第一种:方式需要手动加入一个头结点

//前插操作:在p结点之前插入元素 e
bool InsertPriorNode(LinkList L,LNode *p,ElemType e)

b、第二种将要插入的数据,插入到需要插入的数据的后面,并交换两个结点数据的值

//前插操作:在p结点之前插入元素e
bool InsertPriorNode(LNode *p,ElemType e){
	if(p == NULL){
		return false;
	}
	LNode *s = (LNode *)malloc(sizeof(LNode));
	if(s==NULL){		//内存分配失败 
		return false;
	}
	s->next = p->next;
	p->next=s;			//新结点s连接到p之后 
	s->data=p->data;	//将p中的元素复制到s当中 
	p->data=e;			//p中元素覆盖为e 
	return true;
} 



或者按照下面这个情况

//前插操作:在p结点之前插入结点s
bool InsertPriorNode(LNode *p,LNode *s) {
	if(p == NULL || s == NULL){
		return false;
	}
	s->next = p->next;
	p->next = s;			//s连接p之后 
	ElemType temp = p->data;//交换数据域部分 
	p->data = s->data;
	s->data = temp;
	return true; 
}

6、按位序删除(带头结点)

ListDelete(&L,i,&e):删除操作。

删除表L中第i个位置的元素,并用e返回删除的值。

(找到第i-1个结点,将其指向第i+1个结点,并释放第i个结点)

使用free函数释放空间

a、第一种情况:如果i=4的情况下


#include<stdio.h>
typedef struct LNode{
	ElemType data;
	struct LNode *next;
}LNode,*LinkList;

bool ListDelete(LinkList &L,int i,ElemType &e){
	if(i < 1){
		return true;
	}
	LNode *p;	//指针p指向当前扫描到的结点 
	int j = 0;	//当前p指向的是第几个结点 
	p = L;		//L指向头结点,头结点是第0个结点(不存数据) 
	while(p!=NULL && j <i-1){	//循环找打第i-1个结点 
		p=p->next;
		j++:
	}
	if(p==NULL){ //i值不合法 
		return false;
	}
	if(p->next == NULL){ //第i-1个结点之后已无其他结点 
		return false;
	}
	LNode *q = p->next;//领q指向被删除的结点 
	e = p->next;//用e返回元素的值 
	p->next = q->next;//将*q结点从链中“断开”
	free(q);		//释放结点的存储空间
	return true;   //删除成功
}


(1)删除指定的给定的结点

//删除指定结点p
bool DeleteNode(LNode *p){
	if(p==NULL){
		return false;
	}
	LNode *q = p->next;   //令q指向*p的后继结点 
	p->data=p->next->data;//和后继结点交换数据域 
	p->next=q->next;//将*q结点从链中"断开" 
	free(q);    //释放后继结点的存储空间 
	return true;
	
} 



(2)如果p是最后的一个结点



7、单链表(按位查找,按值查找)(注意:本节只讨论“带头结点”的情况)

(1)按位查找

a、边界情况:如果i=0
//按位查找,返回第i个元素(带头结点)
LNode * GetElem(LinkList L,int i){
	
	if(i<0){
		return NULL;
	}
	LNode *p;//指针p指向当前扫描的结点
	int j = 0;
	p = L;//L指向都结点,头结点是第0个结点(不存储数据)
	while(p!=NULL && j < i){
		p=p->next;
		j++;
	} 
	return p;
}

边界情况
(1)如果i=0

b、边界情况:如果i=8

//按位查找,返回第i个元素(带头结点)
LNode * GetElem(LinkList L,int i){
	
	if(i<0){
		return NULL;
	}
	LNode *p;//指针p指向当前扫描的结点
	int j = 0;
	p = L;//L指向都结点,头结点是第0个结点(不存储数据)
	while(p!=NULL && j < i){
		p=p->next;
		j++;
	} 
	return p;
}
c、普通情况:如果i=3

//按位查找,返回第i个元素(带头结点)
LNode * GetElem(LinkList L,int i){
	if(i<0){
		return NULL;
	}
	LNode *p;//指针p指向当前扫描的结点
	int j = 0;
	p = L;//L指向都结点,头结点是第0个结点(不存储数据)
	while(p!=NULL && j < i){//循环找到第i个结点 
		p=p->next;
		j++;
	} 
	return p;
} 


(2)封装对上述代码进行封装


(3)按值查找

a、第一种情况:如果e=8

b、第二种情况:e=6

如果没有找到直接返回NULL


平均时间复杂度

(4)求表的长度


8、单链表的建立

(1)尾插法建立单链表

a、直接插入
#include<stdio.h>
typedef struct LNode{
	ElemType data;
	struct LNode *next;
}LNode, *LinkList;
//初始化一个单链表(带头结点)
bool InitList(LinkList &L){
	L = (LNode *)malloc(sizeof(LNode));  //分配一个头结点 
	if(L==NULL)			//内存不足,分配失败 
		return false;	 
	L->next = NULL;	//头结点之后暂时还没有节点 
	return true;
} 
void test(){
	LinkList L;//声明一个指向单链表的指针
	//初始化一个空表
	InitList(L);
	//.....后续的代码..... 
} 
//在第i个位置插入元素e(带头结点)
bool ListInsert(LinkList &L,int i,ElemType e){
	
	if(i<1)
		return false;
	LNode *p;//指向p指向当前扫描的结点
	int j = 0;
	p = L;
	while(p!=NULL && j < i-1){
		p = p->next;
		j++;
	} 
	if(p==NULL)
		return false;
	LNode *s = (LNode *)malloc(sizeof(LNode));
	s->data = e;
	s->next = p->next;
	p->next = s;
	return true;//插入成功 
	
} 
//尾插法建立单链表
//初始化单链表
//设置变量length记录的链表长度

//While 循环{
//		每次取一个数据元素e;
//		ListInsert(L,length+1,e)
//		length++; 
//} 

以上算法进行插入操作
每次都从头开始之后遍历,时间复杂度为O(n^2)

b、实现后插操作(带头结点)
//后插操作:在p结点之后插入元素e
bool InsertNextNode(LNode *p,ElemType e){
	if(p == NULL)
		return fasle;
	LNode *s = (LNode *)malloc(sizeof(LNode)以上是关于C/C++语言数据结构快速入门(代码解析+内容解析)链表(单链表,双链表,循环链表,静态链表)的主要内容,如果未能解决你的问题,请参考以下文章

C/C++语言数据结构快速入门(代码解析+内容解析)栈的应用

C/C++语言数据结构快速入门(代码解析+内容解析)栈

C/C++语言数据结构快速入门(代码解析+内容解析)栈

C/C++语言数据结构快速入门(代码解析+内容解析)队列的应用

C/C++语言数据结构快速入门(代码解析+内容解析)特殊矩阵

C/C++语言数据结构快速入门(代码解析+内容解析)队列