静态链表和动态链表的实现

  • Post author:
  • Post category:其他


静态链表

使用静态链表存储数据,需要预先申请足够大的一整块内存空间,也就是说,静态链表存储数据元素的个数从其创建的那一刻就已经确定,后期无法更改。

比如,如果创建静态链表时只申请存储 10 个数据元素的空间,那么在使用静态链表时,数据的存储个数就不能超过 10 个,否则程序就会发生错误。

不仅如此,静态链表是在固定大小的存储空间内随机存储各个数据元素,这就造成了静态链表中需要使用另一条链表(通常称为”备用链表”)来记录空间存储空间的位置,以便后期分配给新添加元素使用,如图 2 所示。

这意味着,如果你选择使用静态链表存储数据,你需要通过操控两条链表,一条是存储数据,另一条是记录空闲空间的位置。

动态链表

使用动态链表存储数据,不需要预先申请内存空间,而是在需要的时候才向内存申请。也就是说,动态链表存储数据元素的个数是不限的,想存多少就存多少。

同时,使用动态链表的整个过程,你也只需操控一条存储数据的链表。当表中添加或删除数据元素时,你只需要通过 malloc 或 free 函数来申请或释放空间即可,实现起来比较简单。

共同点

静态链表和动态链表的共同点是,数据之间”一对一”的逻辑关系都是依靠指针(静态链表中称”游标”)来维持,仅此而已。



划重点


:想进一步学习静态链表的构造思想,可参考

数据结构-静态链表

这篇博客,博主也是通过这篇blog对静态链表的结构和实现过程有了充分的学习

代码:静态链表

使用std::vector创建的静态链表代码如下

/*
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 
 *                                                                                                 
 * Blog: https://blog.csdn.net/weixin_41234001                                      
 *                                                                                                 
 * Author: DoBetter                                                               
 *                                                                                                 
 * Time: 2019.12.02                                                                            
 *                                                                                                 
 * Describe: 使用std::vector实现一个静态链表,包含插入,删除,查找功能                                            
 *           主要思路:通过在vector中定义两个链表,一个为备用链表:用来存储释放的结点空间,一个为数据链表:用来存储数据
 *           vector的第一个元素,即下标为0的元素的next就存放备用链表的第一个结点的下标;
 *           而vector的最后一个元素的next则存放第一个有数值的结点的下标,相当于单链表的头节点作用,当整个链表为空时,则为mynull,表示无指向
 *           
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 
 */
#include <iostream>
#include <vector>
#include <algorithm>
#define mynull -1//定义空值
//定义静态链表结构
typedef int dataType;

const int maxn = 1000;//静态链表的默认大小
struct node
{
	dataType data;//数据域
	int next;//指针域
};

//将链表中各分量链成备用链表
//list[0]为备用链表的头指针,list[maxn-1]为数据链表的头指针,“-1”表示为空
void initList(std::vector<node> &list)
{
	printf("链表初始化\n");
	for (int i=0;i<maxn-2;i++)
	{
		list[i].next = i + 1;
	}
	list[maxn - 2].next = mynull;//因为最后一个元素为链表头结点,所以其前一个结点的指针域为空
	list[maxn - 1].next = mynull;//数据链表的初始头结点的next为空
	return;
}
//返回备用链表的中的第一个结点的位置
int mallocEmptyNode(std::vector<node> &list)
{
	int k = list[0].next;//备用链表的下一个结点地址
	if (k!=mynull)//表示当前有空闲区域进行存储
	{
		list[0].next = list[k].next;//获取到下一个备用结点的地址
	}
	return k;
}
//将下标为pos的空闲结点回收到备用链表中
void freeEmptyNode(std::vector<node> list,int pos)
{
	list[pos].next = list[0].next;
	list[0].next = pos;
}
//获取链表长度
int listLength(std::vector<node> list)
{
	int len = 0;
	int p = list[maxn - 1].next;//第一个结点的地址
	while (p!=mynull)
	{
		len++;
		p = list[p].next;//后移
	}
	return len;
}
//插入结点到链表中
//在array中第pos元素之前插入新的数据元素elem
void listInsert(std::vector<node> &list, int pos, dataType elem)
{
	//printf("插入元素:\n");
	if (pos<1||pos>listLength(list)+1)
	{
		printf("插入位置不合法");
		return;
	}
	int q = mallocEmptyNode(list);//获取分配的备用链表的空间
	if (q!=mynull)
	{

		int p = maxn - 1;//数据链表的头结点位置
		for (int i = 0; i < pos - 1; i++)//寻找插入位置
		{
			p = list[p].next;
		}
		list[q].next = list[p].next;
		list[p].next = q;
		list[q].data = elem;//赋值
	}
	
}
//删除
//删除第pos个元素
void listDelete(std::vector<node> &list, int pos)
{
	//printf("删除元素\n");
	if (pos<1 || pos>listLength(list) + 1)
	{
		printf("删除位置不合法或当期没有元素\n");
		return;
	}
	int p = maxn - 1;
	for (int i=0;i<pos-1;i++)//寻找删除位置的前驱结点的地址
	{
		p = list[p].next;
	}
	int delPos = list[p].next;
	list[p].next = list[list[p].next].next;//结点相连
	freeEmptyNode(list, delPos);//释放结点
}
//遍历链表
void listTraverse(std::vector<node> list)
{
	int p =list[maxn - 1].next;
	while (p!=mynull)
	{
		printf("%d ", list[p].data);
		p = list[p].next;//后移
		if (p==mynull)
		{
			printf("\n");
		}
	}
}
//查找元素
void listSearch(std::vector<node> list,dataType elem)
{
	int p = list[maxn - 1].next;
	while (p != mynull)
	{
		if (elem==list[p].data)
		{
			printf("找到了元素\n");
			return;
		}
		//printf("%d ", list[p].data);
		p = list[p].next;//后移
	}
	printf("没找到\n");
}
int main()
{
	//声明链表
	std::vector<node> list(maxn);
	int n;
	initList(list);//初始化链表
	//插入元素
	printf("插入元素:\n");
	for (int i=1;i<=20;i++)
	{
		listInsert(list, i, i * i);
	}
	//输出
	listTraverse(list);
	//查找元素
	printf("查找元素4:\n");
	listSearch(list, 4);//有该元素
	printf("查找元素99:\n");
	listSearch(list, 99);//无该元素
	//删除元素
	printf("删除第二个元素:\n");
	listDelete(list, 2);
	//输出
	listTraverse(list);
	return 0;
}

代码:动态链表

/*
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 
 *                                                                                                 
 * Blog: https://blog.csdn.net/weixin_41234001                                      
 *                                                                                                 
 * Author: DoBetter                                                               
 *                                                                                                 
 * Time: 2019.11.30                                                                            
 *                                                                                                 
 * Describe: 动态链表                                          
 *                                                                                                 
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 
 */
#include <iostream>
#include <algorithm>
#include <stdlib.h>
using namespace std;
typedef int dataType;
struct node
{
	dataType data;//数据域
	node* next;//指针域
};
//创建链表
node* create(int Array[])
{
	node* p, * pre, * head;//p为新建结点,pre保存当前结点的前驱结点,head为头结点
	head = new node;//创建头结点
	head->next = NULL;//头结点不需要数据域,指针域初始为NULL
	pre = head;//记录pre为head
	for (int i=0;i<5;i++)
	{
		p = new node;//新建结点
		//将Array[i]赋给新建的结点作为数据域,也可以scanf输入
		p->data = Array[i];
		p->next = NULL;//后继结点设为空
		pre->next = p;//前驱结点的指针设为当前新建结点的地址
		pre = p;//将pre移到新建结点上
	}
	return head;//返回头结点
}
//查找
void search(node* root, dataType x)
{
	root = root->next;//从第一个结点开始
	while (root!=NULL)
	{
		if (root->data==x)
		{
			printf("找到了该元素\n");
			return;
		}
		root = root->next;//移动到第二个结点
	}
	printf("不存在该元素");
}
//插入
void insert(node* head, int pos, int x)//pos是位置,x为插入的元素
{
	node* p = head;
	for (int i=0;i<pos-1;i++)
	{
		p=p->next;//pos-1是要插入的位置前一个元素
	}
	node* temp=p->next;//保存p的后继结点
	node* q = new node;//增加的新结点
	q->data = x;//赋值
	p->next = q;//p的下一个结点为新建结点q
	q->next = temp;//新建结点的下一个结点为p的后继结点
}
//删除——删除链表中的所有x
void del(node* head, int x)
{
	node* p, *pre;
	pre = head;//指向p指向的结点的前驱结点
	p = head->next;//从第一个结点开始找
	while (p!=NULL)
	{
		if (p->data==x)//找到了元素x
		{
			pre->next = p->next;//pre的后继结点为p的后继结点
			delete(p);//删除p所指向的结点
			p = pre->next;//p指向pre的后继结点
		}
		else//未找到,则一直往后找
		{
			pre = p;
			p = p->next;
		}
	}

}
//输出
void printList(node* head)
{
	node* p = head->next;
	while (p != NULL)
	{
		printf("%d ", p->data);
		p = p->next;//切换到下一个结点
	}
}
int main()
{
	int Array[5];
	for (int i=0;i<5;i++)
	{
		Array[i] = i * i;
	}
	//创建链表——该链表具有头结点
	node* root = create(Array);
	cout << "链表中的原始数据为" << endl;
	//输出
	printList(root);
	cout << endl;
	//插入
	insert(root, 2, 666);
	//输出
	cout << "插入666后" << endl;
	printList(root);
	cout << endl;
	//查找
	search(root, 0);
	//删除
	del(root, 1);
	//输出
	cout << "删除1后" << endl;
	//输出
	printList(root);
	return 0;
}

参考资料


数据结构:静态链表


静态链表和动态链表的区别详解



版权声明:本文为weixin_41234001原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。