数据结构之链表

十年热恋 提交于 2020-03-05 19:51:04

1.单链表

  • 线性表的链式存储结构的特点是用一组任意的存储单元存储线性表的数据元素
    在这里插入图片描述
    在这里插入图片描述
  • 有时,我们在单链表的第一个节点之前附设一个结点,称为头结点。它的数据部分是空的或者存储链表的长度,指针指向第一个节点的指针
  • 单链表的定义
typedef int ElemType;
typedef struct
{
	ElemType data;
	Node* next;
}Node,*LinkList;
  • 给出索引得到对应单链表元素的值
    由此可见存取元素比顺序线性表要麻烦
    若1<i<n,则频度为i-1,否则为n,所以时间复杂度为O(n)
bool GetElem_L(LinkList &L,int i,ElemType &e)
{
	int j = 0;
	Node *p = L->next;
	while (p && j < i)
	{
		p = p->next;
		++j;
	}
	if (!p) return false;
	e = p->data;
	return true;
}
  • 实现单链表的插入
    时间复杂度为:
    O(n)
    在这里插入图片描述
bool ListInsert_L(LinkList& L, int i, ElemType e)
{
	int j;
	Node* p = L->next;
	//首先寻找到i-1的指针
	while (p && j < i-1)
	{
		p = p->next;
		++j;
	}
	if (!p) return false;
	Node* newNode = (Node*)malloc(sizeof(Node));
	newNode->data = e;
	newNode->next = p->next;
	p->next = newNode;
	return true;
}
  • 实现单链表的删除
    时间复杂度为:
    O(n)
    在这里插入图片描述
bool ListDelete_L(LinkList& L, int i, ElemType& e)
{
	int j;
	Node* p = L->next;
	//首先寻找到i-1的指针
	while (p && j < i-1)
	{
		p = p->next;
		++j;
	}
	if (!p) return false;
	e = p->next->data;
	p->next = p->next->next;
	free(p->next);
	return true;
}
  • 从表尾到表头逆向建立单链表的算法
bool CreateList_L(LinkList& L, int n)
{
	L = (Node*)malloc(sizeof(Node));
	if (!L)  return false;
	L->next = nullptr;
	for (int i = 0; i < n; i++)
	{
		Node* newNode = (Node*)malloc(sizeof(Node));
		if (!newNode)  return false;
		scanf("%d", &newNode->data);
		//插入到头结点后
		newNode->next = L->next;
		L->next = newNode;
	}
	return true;
}
  • 将两个有序链表并为一个有序链表
    与顺序线性表相比时间复杂度都是O(n),但是空间复杂度小于顺序线性表,顺序线性表需要三个空间,而链表只需要两个。c链表只是将a、b链表串起来而已
void MergeList_L(LinkList& la, LinkList& lb, LinkList& lc)
{
	Node* pa = la->next, *pb = lb->next,*pc = lc;
	lc = la;
	//当pa和pb都没有遍历完时
	while (pa && pb)
	{
		if (pa->data < pb->data)
		{
			pc ->next = pa;
			pc = pa;
			pa = pa->next;
		}
		else
		{
			pc->next = pb;
			pc = pb;
			pb = pb->next;
		}
	}
	if (pa)
		pc->next = pa;
	if(pb)
		pc->next = pb;
	//将b毁掉不需要了
	free(lb);
}

2.静态链表

  • 静态链表的表示
#define MAXSIZE 1000 //链表的最大长度
typedef ElemType int;
typedef struct
{
	ElemType data;
	int next_index;
}component,SLinkList[MAXSIZE];
  • 静态链表实质上就是用一个整型变量代替指针,优点就是将顺序存储和动态链接结合起来,比如说S[0].next_index的值是2,则指向的就是S[2],比较麻烦的就是需要用户自己实现malloc和free

3.循环链表

  • 循环链表的特点是表中最后一个结点的指针域指向头结点,整个链表形成一个环
  • 循环链表操作和线性表基本一致,差别仅在于算法中的循环条件不是p或p->next是否为空,而是判断是否指向的是头指针
  • 有的时候,若在循环链表中设立尾指针而不设头指针,可以使某些操作简化。

4.双向链表

  • 双向链表的表示
typedef struct
{
	ElemType data;
	DUNode *prior;
	DUNode *next;
}DuNode,*DuLinkList;
  • 双向链表中的删除和插入都需要修改两个方向上的指针,时间复杂度都为O(n)

5.优缺点

  • 优点:链表在空间的合理利用上和插入、删除时不需要移动等
  • 缺点:求线性表的长度时不如顺序存储结构等。
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!