数据结构线性表学习笔记(2)

前言

书接上文,前面叙述了线性表的顺序表和单链表,本文讲继续介绍线性表的有关知识。

双链表

在前面我们介绍过单链表,可知单链表的每个节点都会包含一个指向后继节点的指针,这样便于我们访问后继节点。但是我们在使用单链表时,经常要找到前一个节点。如果要找到尾节点,要遍历链表才能找到。双链表类似单链表,不同的是每一个节点不仅仅包含一个指向后继节点的指针,还含有一个指向前驱节点的指针,因此可以说它是双向的。

请添加图片描述

typedef struct DNode
{
	ElemType data;        //存放元素
	struct DNode * pri;    //指向前驱结点
	struct DNode * next;    //指向后继结点
}DLinkNode;

1.创建
类似单链表,双链表任然有头插法和尾插法

  • 头插法
void CreatList(DLinkNode * &L, ElemType a[], int n)
{
	int i;
	DLinkNode * s;
	L = (DLinkNode *)malloc(sizeof(DLinkNode));
	L -> pri = NULL;
	L -> next = NULL;
	for(i = 0; i < n; i ++)
	{
		s = (DLinkNode *)malloc(sizeof(DLinkNode));
		s -> data = a[i];
		s -> next = L -> next;
		if(L -> next != NULL)
		{
			L -> next -> pri = s;
		}
		L -> next = s;
		s -> pri = L;
	}
}
  • 尾插法
void CreatList(DLinkNode * &L, ElemType a[], int n)
{
	int i;
	DLinkNode * s, r;
	L = (DLinkNode *)malloc(sizeof(DLinkNode));
	r = L;
	for(i = 0; i < n; i ++)
	{
		s = (DLinkNode *)malloc(sizeof(DLinkNode));
		s -> data = a[i];
		r -> next = s;
		s -> pri = r;
		r = s;
	}
	r -> next = NULL;
}

2.插入

s结点
s = (DLinkNode *)malloc(sizeof(DLinkNode));
s -> data = e;
在p结点后插入s结点
p -> next = s -> next;   //1
p -> next -> pri = s;    //2
s -> pri = p;            //3
p -> next = s;           //4

请添加图片描述

3. 删除
找到要删除的结点q和他的前驱结点p

方法1
p -> next = p -> next;
q - > next -> pri = p;

方法2
p -> next = q -> next;
q -> next -> pri = p;

最后
free(q);

请添加图片描述

4. 基本运算
双链表其他运算于单链表类似,这里给出之前的链接
单链表

循环链表

循环链表即在单链表和双链表的基础上实现循环,即头结点和尾节点之间相连构成循环
其基本运算于对应的非循环链表基本相同,主要差别是对于链表来说判断其尾结点p的依据是
p -> next = L,同样可以通过L -> prior 找到尾结点

有序表

1.定义
线性表的元素按递增或递减的方式排列

2.基本运算算法
有序表的基本运算与前面的顺序表和链表大致相同,下面列出不同处

  1. 顺序表的插入
    不同处在于插入要按顺序插入
	找出插入位置:
	while(i < L -> length && L -> data[i] < e)   e为插入元素
		i ++;
	当找到要插入的位置后,须将此位置空出来,为此将i位置后的每一元素后移一位
	for(j = L -> length; j > i; j --)
	{
		L -> data[j] = L -> data[j - 1];
	}
	实现i位置后的每一个元素后移一位,i位置空出
	L -> data[i] = e;
	L -> length ++;
  1. 链表的插入
	找到要插入的位置
	while(p -> next != NULL && p -> next -> data < e)
		p = p -> next;
	找到后直接插入
	q = (LinkNode *)malloc(sizeof(LinkNode));
	q -> data = e;
	q -> next = p -> next;
	p -> next = q;

3. 归并算法
现有两个有序表LA,LB,要求将其合并且不破坏LA,LB

思路:构建一个新的有序表LC,同时扫描LA和LB,将二者中较小的元素放入LC中,然后再从LC获取较小元素
的有序表中选取下一个元素继续比较,直到二者中有一个率先结束扫描,再将剩下元素放入LC中(二路归并)
以单链表为例
void UnionList(LinkNode * &LA, LinkNode * &LB, LinkNode * &LC)
{
	LinkNode * pa =LA -> next, * pb = LB -> next;   //pa,pb均是指首结点
	LinkNode * r, *s;
	LC = (LinkNode *)malloc(sizeof(LinkNode));
	r = LC;
	while(pa -> next != NULL && pb -> next != NULL)
	{
		if(pa -> data < pb -> data)     //将两者较小的值插入到LC中
		{
			s = (LinkNode *)malloc(sizeof(LinkNode));
			s -> data = pa -> data;
			s-> next = r -> next;
			r -> next = s;	
			pa = pa -> next;
		}
		else
		{
			s = (LinkNode *)malloc(sizeof(LinkNode));
			s -> data = pb -> data;
			s-> next = r -> next;
			r -> next = s;	
			pb = pb -> next;
		}
	}
	//跳出循环,将剩下的元素插入到LC中
	while(pa != NULL) //将剩下的元素复制到LC中
	{
		s = (LinkNode *)malloc(sizeof(LinkNode));
		s -> data = pa -> data;
		s -> next = r -> next;
		r -> next = s;
		pa = pa -> next;
	}
	while(pb != NULL) //将剩下的元素复制到LC中
	{
		s = (LinkNode *)malloc(sizeof(LinkNode));
		s -> data = pb -> data;
		s -> next = r -> next;
		r -> next = s;
		pb = pb -> next;
	}
	r -> next = NULL;
}

小结

本文主要学习了双链表以及有序表,对照之前的单链表和顺序表,会发现其实并不难,同时也要注意到,在学习一种新的抽象结构中我们应该对照所学过的结构,这样学起来会很轻松

总结

本文连同上文简单的介绍了线性表的逻辑结构,两种存储结构,基本运算以及有序表,在学习的过程中不仅仅是认识了一种常见的线性结构,更加深了我们对于C语言指针和结构体的理解和掌握,为接下来学习栈和队列,奠定基础

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值