数据结构之 - 线性表 笔记总结

本文总结了数据结构中的线性表,包括它的定义、四个基本特征、顺序表和链表两种存储结构,以及链表的五种形式。详细探讨了线性表在C语言中的结构体定义,以及顺序表、单链表和双链表的操作,如插入、合并和逆置等。
摘要由CSDN通过智能技术生成

数据结构之线性表

概念定义

线性表是具有相同特性元素的一个有限序列,序列中元素的个数叫做线性表的长度,用n表示,n>=0,等于0时代表线性表是一个空表

线性数据结构的4个基本特征

1、集合中有且仅有一个“第一个元素”
2、集合中有且仅有一个“最后一个元素”
3、除最后一个元素外,其他元素均有唯一的后继元素
4、除第一个元素外,其他元素均有唯一的一个前驱元素

线性表的两种存储结构

1、第一种:顺序表

表中所有元素都按照其逻辑顺序,依次存储到一块连续的存储空间中

顺序表支持“随机访问特性”,因为存储是开辟的一块存储空间时连续的,我们很容易通过类似下标的概念,访问这块存储空间的任何一块的内容

2、第二种:链表

链表结构中,每个结点,不仅仅会存储这个结点的元素值信息,还会存储与其他结点之间的逻辑关系信息,比如前驱结点指向元素的指针地址信息,后继元素指向的指针地址信息

链表不支持“随机访问特性”,如果想访问这个链表种的最后一个结点,必须从第一个结点开始访问,才能根据第一个结点的“后继”元素的地址指针,访问到第二个元素,之后重复这个过程,依次才能访问到最后一个结点元素

因为链表的这个结 构特性,数据可以分散的存储在内存中的任意的位置,只需要通后结点的“前驱”地址指针和“后继”地址指针指向这块内存地址就可以访问到;并且链表不需要一次性的分配全部将要使用的地址空间(有时你也不知道你这一次到底要使用多少的空间),那么链表结构支持存储空间的动态分配,可以做到随用随分配

链表的5种形式

单链表、双链表、循环单链表、循环双链表、静态链表

请看下面的灵魂草图8⃣️
在这里插入图片描述在这里插入图片描述

线性表的结构体定义(基于C语言)

顺序表的结构体定义

#define maxSize 100

typedef struct
{
	//顺序表数组元素
	int data[maxSize];
	//顺序表长度
	int length;
}Sqlist

单链表的结构体定义

typedef struct LNode
{
	//结点中的数据区
	int data;
	//后继结点的指针
	struct LNode *node;
}

双链表的结构体定义

typedef struct DLNode
{
	//结点中的数据区
	int data;
	//前驱结点指针
	struct DLNode *prior;
	//后继结点指针
	struct DLNode *next;
}

顺序表的操作

例题:
已知一个顺序表,其中的元素递增有序排列,插入一个元素x后,使该顺序表仍然有序递增

int findElem(Sqlist L, int x)
{
	for(int i=0; i<L.length; i++)
	{
		if(x<L.data[i])
		{
			return i;
		}
	}
	//顺序表中不存在比x大的元素,则应插入到顺序表表尾
	return i;
}
void insertELem(Sqlist &L, int x)
{

	int p = findELem(L, x);
	for(int i=L.length-1; i>=p; --i)
	{
		L.data[i+1] = L.data[i];
		L.data[p] = x;
		++(L.length);
	}
}

单链表的操作

例题:
A和B是两个带有头结点的单链表,A和B中的元素都是递增有序的。设计一个算法,将A和B合并成一个按元素值非递减有序链表C

以下代码使用的是尾插法进行插入链表的操作,类似的插入操作还有头插法

void merge(LNode *A, LNode *B, LNode *&C)
{
	LNode *p = A -> next;
	LNode *q = B -> next;
	LNode *r;
	C = A;
	C -> next = NULL;
	free(B);
	r = C;
	while(p!=NULL && q!=NULL)
	{
		if(p -> data <= q -> data)
		{
			r -> next = p;
			p = p -> next;
			r = r ->next;
		}
		else
		{
			r -> next = q;
			q = q-> next;
			r = r ->next;
		}
	
	}
	r -> next = NULL;
	if(p != NULL)
	{
		r -> next = p;
	}
	if(q != NULL)
	{
		r -> next = q;
	}
}

双链表的操作

使用尾插法建立双链表

void createDlistR(DLNode *&L, int a[], int n)
{
	DLNode *s, *r;
	int i;
	L = (DLNode*)malloc(sizeof(DLNode));
	L -> prior = NULL;
	L -> next = NULL;
	r = L;
	for(i = 0; i < n; ++i)
	{
		s = (DLNode*)malloc(sizeof(DLNode));
		s -> data = a[i];
		r -> next = s;
		s -> prior = r;
		r = s;
	}
	r -> next = NULL;
}

双链表查找结点的方法

DLNode* findNode(DLNode *C, int x)
{
	DLNode *p = C -> next;
	while(p != NULL)
	{
		if(p -> data == x)
			break;
		p = p -> next;
	}
	return p;
}

向双链表中插入结点的方法

s -> next = p -> next;
s -> prior = p;
p -> next = s;
s -> next -> prior = s;

删除双链表中结点的方法

q = p -> next;
p -> next = q -> next;
q -> next -> prior = p;
free(q);

逆置问题🌟

线性表元素逆置操作

void reverse(int a[], int firstIndex, int lastIndex, int k)
{
	int temp;
	for(int i = firstIndex,j = lastIndex; i < firstIndex + k && i < j; ++i,--j)
	{
		temp = a[i];
		a[i] = a[j];
		a[j] = temp;
	}
}

将数组中的元素,循环左移p个位置(0<p<n)

//整体思路:先将0~p-1位置元素逆置,再将p~n-1位置元素逆置,最后再将整个数组逆置
void(int a[], int n, int p)
{
	reverse(a, 0, p-1, p);
	reverse(a, p, n-1, n-p);
	reverse(a, 0, n-1, n);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值