数据结构算法刷题笔记——二、线性结构(2.1线性表)

2.1 线性表的顺序存储实现

2.1.1 数据结构定义

typedef struct LNode *List;
struct LNode{
	ElementType Data[MAXSIZE];
	int Last;
};
struct LNode L;
List Prtl;
  • MAXSIZE为Data数组的最大长度(确定值)
  • Last指向数组中存储的最后一个元素n,下标为n-1
  • 线性表的长度为:L.Last+1 或 Ptrl->Last+1

2.1.1.1 主要操作

  • List MakeEmpty();//初始化一个空线性表L;
  • ElementType FindKth( int K, List L );//根据位序K,返回相应元素;
  • int Find( ElementType X, List L ):在线性表L中查找X的第一次出现位置;
  • void Insert( ElementType X, int i, List L):在位序i前插入一个新元素X;
  • void Delete( int i, List L ):删除指定位序i的元素;
  • int Length( List L ):返回线性表L的长度n。

2.1.1.2 主要操作实现

1. 初始化(建立空的顺序表)
List MakeEmpty()
{
	List Ptrl;
	Ptrl = ( List )malloc( sizeof(struct LNode) );//申请内存空间
	Ptrl->Last = -1;//空表没有元素,则长度为-1,0表示有一个元素
	return Ptrl;
}
2 查找

查找X值在表中的位置,返回位置序号

int Find( Elementype X, List Ptrl )
{
	int i = 0;
	while( i <= Ptrl->Last && Ptrl -> Data[i] != X )
		i++;
	if( i > Ptrl->Last )
		return -1;		//没有查找到对应值,返回-1
	else
		return i;		//找到返回后的之,返回存储位置
}
  • 查找成功的平均比较次数为(n+1)/2
  • 平均十进性能为O(n)
3 插入

第i( 1 <= i <= n+1)个位置上插入一个值为X的新元素

void Insert( ElementType X, List Ptrl )
{
	int j;
	//表空间已满,不能再插入
	if( Ptrl->Last == MAXSIZE-1){
		printf( "表满" );
		return;
	}
	//检查插入位置是否合法
	if( i < 1 || i > Ptrl->Last+2 ){
		printf( "位置不合法" );
		return;
	}
	//以上没有问题,进行插入操作
	for( j = Ptrl->Last; j >= i-1; j--)
		Ptrl->Data[j+1] = Ptrl->Data[j];
	Ptrl->Data[i-1] = X;
	Ptrl->Last++;
	return;
}
  • i < Ptrl->Last+2 的由来
    • 假设链表共有n个元素
    • Ptrl->Last指向的是第n个元素,即Ptrl->Data[n-1]元素
    • i < Ptrl->Last+2,即 i < n-1+1+1 , i < n+1 ,则可以有 i = n+1
    • 在向i的位置插入X时需要对i-1处理,则插入到Ptrl-Data[i-1],即插入到Ptrl->Data[n]的位置
    • 没有留下空位,则可以插入
4 删除
void Delete( int i, List Ptrl )
{
	int j;
	//判断删除的元素是否在数组元素范围之内
	if( i <1 || i > Ptrl->Last+1 ){
		printf( "不存在第%d个元素", i )return;
	}
	//删除指定元素
	//实现方式是将其后元素依次前移
	for( j = i; j <= Prtl->Last; j++ ){
		Ptrl->Data[i-1] = Ptrl->Data[i];
	}
	Ptrl->Last--;//指向删除后的最后元素
	return;
}

2.2 线性表的链式存储实现

2.2.1 数据结构定义

typedef struct LNode *List;
struct LNode{
	ElementType Data;
	List Next;
};
struct LNode L;
List Ptrl;
  • 不要求逻辑上相邻的两个元素物理上也相邻
  • 通过链建立数据元素之间的逻辑关系"Next"
  • 插入、删除不需要移动数据元素,只需要修改“链”“Next”
  • 查找元素相对较麻烦

2.1.1.1 主要操作

  1. List MakeEmpty();//初始化一个空线性表L;

  2. ElementType FindKth( int K, List L );//根据位序K,返回相应元素;

  3. int Find( ElementType X, List L ):在线性表L中查找X的第一次出现位置;

  4. void Insert( ElementType X, int i, List L):在位序i前插入一个新元素X;

  5. void Delete( int i, List L ):删除指定位序i的元素;

  6. int Length( List L ):返回线性表L的长度n。

2.1.1.2 主要操作实现

1 初始化(建立空的顺序表)
//随机产生n个元素的值,建立带表头节点的单链表线性表L(头插法)
void MakeEmpty( List *L, int n )
{
	List Ptrl;
	int i;
	srand(time(0));//初始化随机数种子
	*L = ( List )malloc( sizeof(struct LNode) );//申请内存空间
	*L->Next = NULL;//先建立一个带头节点的单链表
	for( i = 0; i < n; i++){
		Ptrl = (List)malloc(sizeof(struct LNode));//生成新节点
		Ptrl->Data = rand()%100+1;//随机生成100以内的数字填充元素内容
		Ptrl->Next = (*L)->Next;
		(*L)->Next = Ptrl;//插入到表头
	}
}
2 求表长
int Length( List Ptrl)
{
	List p = Ptrl;//p指向表的第一个节点
	int j = 0;
	while(p){
		p = p->Next;
		j++;//当前p指向的是第j个节点
	}
	return j;
}
  • 平均时间性能为O(n)
3 查找
3.1 按序号查找
List FindKth( int K, List Ptrl )
{
	List p = Ptrl;
	int i = 1;
	while( p != NULL && i < K){
		p = p->Next;
		i++;
	}
	if( i == K )
		return p;//找到第K个,返回指针
	else
		return NULL;//否则返回空值
}
  • 平均时间性能为O(n)
3.2 按值查找
List Find( ElementType X, List Ptrl )
{
	List p = Ptrl;
	while( p != NULL && p->Data != X ){
		p = p->Next;
	}
	return p;
}
  • 平均时间性能为O(n)
4 插入操作
  • 在第 i - 1 (1 <= i <=n+1)个结点后插入一个值为X的新结点
List Insert( ElementType X, int i, List Ptrl )
{
	List p, s;
	//新结点插入在表头
	if( i == 1 ){
		s = (List)malloc(sizeof(struct LNode));//申请新结点
		s->Data = X;//装填新结点
		s->Next = Ptrl;
		return s; 
	}
	p = FindKth(i-1,Ptrl);//查找第i-1个结点
	if(p == Null){
		printf("参数i错误");//第i-1个不存在,不能插入
		return NULL}
	else{
		s = (List)malloc(sizeof(struct LNode));
		s->Data = X;
		s->Next = p->Next;
		p->Next = s;
		return Ptrl;
	}
}
  • 平均查找次数为n/2
  • 平均是按性能为O(n)
5 删除
  • 删除链表的第 i ( 1 <= i <= n )个位置上的结点
List Delete( int i, List Ptrl )
{
	List p, s;
	//若要删除的是表的第一个结点
	if(i == 1){
		s = Ptrl;
		if(Ptrl != NULL)
			Ptrl = Ptrl->Next;//删除头结点后,头结点指向之前的第二个结点
		else
			return NULL;
		free(s);//释放掉对应想要删除结点的内存空间,即删除结点
		return Ptrl;
	}
	p = FindKth( i-1, Ptrl);
	if( p == NULL ){
		printf("第%d个结点不存在", i-1);
		return NULL;
	}
	else if( p->Next == NULL){
		printf("第%d个结点不存在", i);
		return NULL;
	}
	else {
		s = p->Next;
		p->Next = s->Next;
		free(s);
		return Ptrl;
	}
}
  • 平均查找次数为n/2
  • 平均时间性能为O(n)

2.1.2 参考资料

2.1.2.1 malloc函数

malloc说明

1、malloc的全称是memory allocation(动态内存分配)
2、malloc函数是一种分配长度为num_bytes字节的内存块的函数,可以向系统申请分配指定size个字节的内存空间。
1、返回类型是 void* 类型。void* 表示未确定类型的指针。C,C++规定,void* 类型可以通过类型转换强制转换为任何其它类型的指针。
char *Ptr = NULL;
Ptr = (char *)malloc(100 * sizeof(char));

malloc用法

1、使用前要申明:#include <stdlib.h>或者#include <malloc.h>
2void *malloc(long NumBytes):
      该函数分配了NumBytes个字节,并返回了指向这块内存的指针。如果分配失败,则返回一个空指针(NULL)。分配失败的原因,应该有多种比如说空间不足就是一种。
3void free(void *FirstByte): 
      该函数是将之前用malloc分配的空间还给程序或者是操作系统,也就是释放了这块内存,让它重新得到自由。

malloc重点

1、对返回值进行检查:分配成功则返回指向被分配内存的指针(此存储区中的初始值不确定),否则返回空指针NULL2、使用完毕释放内存:当内存不再使用时,应使用free()函数将内存块释放。

malloc函数与new函数区别

new返回指定类型的指针,并且可以自动计算所需要的大小。
int *p;
p = new int;   //返回类型为int *类型,分配的大小为sizeof(int)
p = new int[100];    //返回类型为int *类型,分配的大小为sizeof(int) * 100
而malloc则必须由我们计算字节数,并且在返回的时候强转成实际指定类型的指针。
int *p;
p = (int *)malloc(sizeof(int));
free(p);
  1. malloc的实参是sizeof(int),用于指明一个整形数据需要的大小,如果我们写成:p = (int
    *)malloc(1),那么可以看出:只是申请了一个字节的空间,如果向里面存放了一个整数的话,将会占用额外的3个字节,可能会改变原有内存空间中的数据;
  2. malloc只管分配内存,并不能对其进行初始化,所以得到的一片新内存中,值是随机的。一般意义上:我们习惯性的将其初始化为NULL。当然,也可以用memset函数的。
    memset是一个初始化函数,作用是将某一块内存中的全部设置为指定的值。
    void *memset(void *s, int c, size_t n);
    char a[4]; memset(a,'1',4);cout << a[i]; 1 1 1 1
    • s指向要填充的内存块。
    • c是要被设置的值。
    • n是要被设置该值的字符数。
    • 返回类型是一个指向存储区s的指针。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值