线性表---苦修内功篇


半年前自学数据结构,初次接触内功尚浅,觉晦涩难懂,而今发现遗忘严重,恰逢学校专业课开设,现复习总结数据结构,分为苦修内功篇和华山论剑篇,分别总结笔者认为数据结构重难点和经典例题实践。

数据结构引言

既然要学习该门课程,自然要了解数据结构讲的是什么,我们学习目标是什么。

注:非官方定义,为笔者所理解给出的定义,望指正!

数据结构定义

数据结构是研究数据元素之间关系的集合。
数据元素之间的关系也被称为结构。
根据数据之间的组织,存储和运算,将其分为逻辑结构,存储结构,和算法。

注意:在数据结构定义中的几个关键词:逻辑结构,存储结构,算法。
而我们学习数据结构就从这三个方面来学习。

逻辑结构

描述数据之间的逻辑关系

分类
  1. 线性结构
  2. 树形结构
  3. 图状结构
  4. 集合结构

存储结构

数据在计算机物理结构中的存储

分类
  1. 顺序映象
  2. 非顺序映象

线性表

注:一些概念性的定义说明在已忽略,如有疑问可自行查找或留言

顺序存储结构

特点:逻辑结构相邻的数据元素,其物理位置也相邻

顺序表基操

1.1顺序存储结构
#define MAXSIZE 20
typedef int ElemType;
typedef struct
{
	ElemType data[MAXSIZE];
	int length;
}SqList;

注意顺序表结构,在此定义的length是必要的,length用于表示线性表当前存储数据元素的个数,即线性表长度。(非数据长度,非数组长度,数组长度为MAXSIZE,为固定的)
注意:以下顺序表存储都从下标1位置开始存储元素

1.2顺序表初始化
void Init_SqList(SqList *L)
{
	L->length = 0;
}
1.3按值查找
int Location_SqList(SqList *L,ElemType x)
{
	int i = 1;
	while(i<=L->length && L->elem[i]!=x)
		i++;
	if(L->length<i)
		return false;
	return i;
}
1.4插入操作
int Insert_SqList(SqList *L,int i,ElemType x)
{
	if(L->length == MAXSIZE) return FALSE;//表满
	if(i<1 || i> L->length+1) return FALSE;//位置非法
	int j;
	for(j=L->length; j>=i; j--)//移动
		L->elem[j+1] = L->elem[j];
	L->elem[i] = x;
	L=>length++;
	return TRUE;
} 

平均复杂度:

所有元素插入等可能,概率P=1/(n+1);
i=1,循环n次;i=2,循环n-1次;…i=n,循环1次;i=n+1,循环0次;
0=(n+(n-1)+(n-2)+(n-3)+…+1+0)*P=O(n/2)

1.4顺序表删除
int Delet_SqList(SqList *L,int i,ElemType *e)
{
	if(L->length == 0) return FLASE;
	if(i<1 || i> L->length) return FALSE;
	*e = L->elem[i];
	int j;
	for(j = i; j<L->length; j++)
		L->elem[j] = L->elem[j+1];
	L->length--;
	return TRUE;
}

平均复杂度:

所有元素删除等可能,概率P = 1 / n;
i = 1, 循环n - 1次;i = 2, 循环n - 2次;…i = n, 循环0次;
0 = ((n - 1) + (n - 2) + (n - 3) + … + 1) *P = O((n - 1) / 2)

1.5顺序表逆置
void Reverse_SqList(SqList *L)
{
	int i;
	ElemType t;
	for(i = 1;i< L->length/2;i++){
		t = L->elem[i];
		L->elem[i] = L->elem[L->length-i+1];
		L->elem[L->length-i+1] = t;
	}
}

链式存储结构

特点:链表中结点的逻辑次序与物理次序不一定相同

单链表

1.1单链表结点定义

typedef struct Node
{
	ElemType data;
	struct Node* next;
}LNode,* LinkList;

1.2.1头插法创建单链表

LinkList Create_LinkList1()
{
	LinkList head = (LinkList)malloc(sizeof(LNode);
	head->next = NULL;
	LNode * s;
	ElemType x;
	scanf("%d",&x);
	while(x!=-1)
	{
		s = (LinkList)malloc(sizeof(LNode));
		s->data =x;
		s->next = head->next;
		head->next = s;
		scanf("%d",&x);
	}
	return head;
}

1.2.2尾插法创建单链表

LinkList Create_LinkList2()
{
	LinkList head = (LinkList)malloc(sizeof(LNode));
	head->next = NULL;
	LNode *s,*r = head;
	ElemType x;
	scanf("%d",&x);
	while(x!=-1)
	{
		s = (LinkList)malloc(sizeof(LNode));
		s->data =x;
		r ->next = s;
		r = s;
		scanf("%d",&x);
	}
	r->next = NULL;
	return head;
}

1.3按序号查找

LinkList Get_LinkList(LinkList head,int k)
{
	LinkList p = head;
	int j = 0;
	while(p->next && j<k)
	{
		p = p->next;
		j++;
	}	//查找到第k个结点
return p;
}

这里注意return p的用意,此时如果没有第k个结点,即p = NULL
1.4单链表插入

int Insert_LinkList(LinkList head,int i,ElemType x)
{
	LinkList p = head,s;
	int j = 0;
	while(p && j<i-1)
	{
		p = p->next;
		j++;
	}
	if(p){
		s = (LinkList)malloc(sizeof(LNode));
		s->data = x;
		s->next = p->next;
		p ->next = s;
		return TRUE;
	}
	return FALSE;
}

注意,单链表插入和删除都应该找到第 i - 1 个结点
1.5单链表删除

int Delete_LinkList(LinkList head,int i,ElemType *x)
{
	LinkList p = head,s;
	int j = 0;
	while(p && j<i-1)
	{
		p = p->next;
		j++;
	}
	if(p)
	{
		s = p->next;
		*x = s->data;
		p->next = s->next;
		return TRUE;
	}
	return FALSE;
}

1.6 链表逆置

LinkList Reverse_LinkList(LinkList head)
{
	LinkList p = head->next,q;
	head->next = NULL;
	while(p)
	{
		q = p->next;
		p ->next = head->next;
		head->next = p;
		p = q; 
	}
	return head;
}

双向链表

1.1双向链表的定义

typedef struct DLNode
{
	ELemType data;
	struct dlnode *prior,*next;
}DLNode,*DLinkList;

双向链表和单链表创建,查找,插入和删除操作基本类似,对插入操作的不同点展示如下:

int Insert_DLinkList(DLinkList head,int i,ElemType x)
{
	DLinkList p = head,s;
	int j = 0;
	while(p && j<i)
	{
		p = p->next;
		j++;
	}//注意,此时p指向的是第i个结点,与单链表指向i-1不同
	if(p){
		s = (DLinkList)malloc(sizeof(DLNode));
		s->data = x;
		//核心连接代码
		s->prior = p->prior;
		p->prior->next = s;
		s->next = p;
		p->prior = s;
		
		return TRUE;
	}
	return FALSE;
}

插入操作中,最核心的是p->prior的指向不能在核心连接操作中丢失,应该在最后进行修改,其他步骤可以交换顺序。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
线性是一种数据结构,它由一组有序的数据元素组成,每个元素都有一个唯一的下标,称为索引。按值查找是指根据给定的值,在线性中查找相应的元素,并输出该元素的位置或值。 实现按值查找的方法通常有两种:顺序查找和二分查找。 顺序查找是从线性的第一个元素开始逐一比较,直到找到目标元素或遍历完整个。代码如下: ```python def sequential_search(lst, value): for i in range(len(lst)): if lst[i] == value: return i # 返回目标元素的位置 return -1 # 示未找到目标元素 ``` 二分查找是在有序中查找目标元素的一种高效算法。它的基本思想是不断缩小查找范围,每次将目标值与中间位置的元素比较,根据比较结果确定下一步查找的范围。代码如下: ```python def binary_search(lst, value): left, right = 0, len(lst) - 1 while left <= right: mid = (left + right) // 2 if lst[mid] == value: return mid # 返回目标元素的位置 elif lst[mid] > value: right = mid - 1 # 缩小右边界 else: left = mid + 1 # 缩小左边界 return -1 # 示未找到目标元素 ``` 下面是一个示例,演示如何在一个有序列中查找目标元素的位置: ```python lst = [1, 3, 5, 7, 9, 11, 13, 15] value = 7 # 使用顺序查找 index = sequential_search(lst, value) print(f"顺序查找:{value}在列中的位置为{index}") # 使用二分查找 index = binary_search(lst, value) print(f"二分查找:{value}在列中的位置为{index}") ``` 输出结果为: ``` 顺序查找:7在列中的位置为3 二分查找:7在列中的位置为3 ``` 注意,二分查找只适用于有序,如果列是无序的,需要先进行排序才能使用二分查找。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Code_Pianist

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值