02-线性表

02-线性表

概念

线性表是具有相同特性数据元素的有限序列

线性表的逻辑结构

相同特性

把一类事物归类,方便批量处理

typedef struct{
	char* name;//char *c = "abc"和char c[]="abc",前者改变其内容程序是会崩溃的,而后者完全正确。
	int IDNumber;
	float height;
}Human;
有限

表中元素个数为n,n无限大,n可以为0

序列

表中元素排成一列,体现了一对一的逻辑特性(每个元素有则仅有一个前驱和后继)

线性表的存储结构

顺序存储空间
image-20210915151939298
int A[maxSize];//maxSize常量
int length=0;
链式存储空间
单链表
image-20210915152448546
typedef struct LNode{
	int data;
	struct LNode *next;
}LNode;

//定义节点
LNode *L;
L=(LNode*)malloc(sizeof(LNode));//为LNode开辟空间并返回地址
A->next=B;//存储B节点的地址到A的next分量中

开始结点:第一个存储数据的结点
头结点:不存储数据的结点
尾结点:最后一个存储数据的结点
判断(单)链表是否为空
image-20210915152906163
双链表
image-20210915153221464
typedef struct DLNode{
	int data;
	struct DLNode *next;
	struct DLNode *prior;
}DLNode;
DLNode *L;
L=(DLNode*)malloc(sizeof(DLNode));
A->next=B; B->next=C; C->next=D;
D->prior=C; C->prior=B; B->prior=A;
判断(双)链表是否为空
image-20210915153630519
(单)循环链表
image-20210915153942685
(双)循环链表
image-20210915154048692
循环链表判空
image-20210915154125632
不带头结点的单双循环链表
image-20210915154246639

顺序存储和链式存储的特性对比–(考点)

特性对比问题

  1. 在顺序表中插入或删除元素可能会导致移动大量元素的连带操作(插入或删除操作发生在表尾位置例外),而链表不会
  2. 线性表采用顺序存储结构,必须占用一片连续的存储单元,而采用链式存储结构则不需要这样;
  3. 从表整体来看,一般顺序表存储空间利用率第一链表;而从单个存储单元来看,顺序表的存储空间利用率高于链表;

插入删除

单链表结点插入操作
image-20210915171843854
s->next = p->next;
p->next = s;
单链表结点删除操作
image-20210915172034857
p->next = s->next;
free(s);
小结
  1. 给链表设置头结点,可以使得在第一个数据结点之前插入一个新结点和删除第一个数据结点的操作同表中部结点的这些操作统一起来,方便写代码;
  2. 带头结点的链表,其头指针值不随操作而改变,可以减少错误;
双链表结点插入操作
image-20210920203852178
s->next = p->next;
s->prior = p;
p->next = s;
s->next->prior = s;
双链表结点删除操作
image-20210920204538693
s->prior->next = s->next;
s->next->prior = s->prior;
free(s);

建表

顺序表建表代码
int A[maxSize];
int length;
int createList(int A[],int &length){
	cin>>length;
	if(length > masSize)
		return 0;
	for(int i=0;i<length;++i){
		cin>>A[i];
	}
	return 1;
}
单链表建表代码
单链表尾插法
void createLinkListR(LNode *&head){
	head = (LNode*)malloc(sizeof(LNode));
	head->next = NULL;
	LNode *p = NULL,*r = head;
	int n;
	std::cin>>n;
	for(int i=0;i<n;++i){
		p = (LNode*)malloc(sizeod(LNode));
		p->next = NULL;
		std::cin>>p->data;
		p->next = r->next;
		r->next = p;
		r = p;
	}
}
输入:	5  12345
输出: 12345
单链表头插法
void createLinkListH(LNode *&head){
	head = (LNode*)malloc(sizeof(LNode));
	head->next = NULL;
	LNode *p = NULL;
	int n;
	std::cin>>n;
	for(int i=0;i<n;++i){
		p = (LNode*)malloc(sizeod(LNode));
		p->next = NULL;
		std::cin>>p->data;
		p->next = head->next;
		head->next = p;
	}
}
输入: 5 12345
输出: 54321

移动次数计算(顺序表)和静态链表

插入移动次数计算(顺序表)
image-20210915161456574
  1. 在任一位置插入元素的概率为:p=1/(n+1);

  2. 在i位置(i的取值:0~n)之前插入元素,需要移动n-i个元素;

  3. 插入元素平均要移动的元素个数为:n/2

    0位置:移动n个元素

    1位置:移动n-1个元素

    n位置:移动0个元素

    总移动次数:(n+0)(n+1)/2

    平均移动次数:【1/(n+1)】(n+0)(n+1)/2=n/2

    删除移动次数计算(顺序表)
    1. 在任一位置删除元素的概率为:p=1/n;
    2. 在i位置(i的取值:0~(n-1))删除元素,需要移动n-1-i个元素;
    3. 删除元素平均要移动的元素个数为:(n-1)/2;
    静态链表
    image-20210915171149460
    typedef struct{
    	int data;
    	int next;
    }SLNode;
    SLNode SLink[maxSize];
    
    int p=A0;		//定义一个指针
    SLink[p].data;	//取p指针指向的结点值,类比p->data;
    SLink[p].next;	//取后继结点指针,类比p->next;
    

归并(二路归并)

顺序表归并
//m为a的长度,n为b的长度,c为归并后的顺序表
void mergearray(int a[],int m,int b[],int n,int c[]){
	int i=0,j=0;
	int k=0;
	while(i < m&&j < n){
		if(a[i]<b[j]){
			c[k]=a[i];k++;i++;//c[k++]=a[i++]
		}else{
			c[k]=b[j];k++;j++;
		}
	}
	while(i < m){
		c[k]=a[i];k++;i++;
	}
	while(j < m){
		c[k]=b[j];k++;j++;
	}
}
链表归并-1
//归并后升序
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;
		}
	}
	if(p!=NULL){r->next = p;}
	if(p!=NULL){r->next = q;}
}
链表归并-2
//归并后降序
void merge(LNode *A,LNode *B,LNode *&c){
	LNode *p = A->next;
	LNode *q = B->next;
	LNode *s;
	C = A;
	C->NEXT = NULL;
	free(B);
	while(p!=NULL&&q!=Null){
		if(p->data <= q->data){
			s = p;
			p = p->next;
			s->next = C->next;
			C->next = s;
		}else{
			s = q;
			q = q->next;
			s->next = C->next;
			C->next = s;
		}
	}
	while(p!=NULL){
		s = p;
        p = p->next;
        s->next = C->next;
        C->next = s;
	}
	while(q!=NULL){
        s = q;
        q = q->next;
        s->next = C->next;
        C->next = s;	
     }
}

逆置

顺序表逆置
for(int i=left,j=right;i>j;i++,j--){
	temp = a[i];
	a[i]=a[j];
	a[j]=temp;
}
将多个元素移动到数组某一位置之后
void reverse(int a[],int left,int right,int k){
	int temp;
	for(int i=left,j=right;i<left+k&&i<j;++i,--j){
		temp = a[i];
		a[i] = a[j];
		a[j] = temp;
	}
}
void moveP(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);
}
链表逆置
image-20210921191626650 image-20210921191811889
//逆置p->next到q之间的结点
while(p->next!=q){
	t = p->next;
	p->next = t->next;
	t->next = q->next;
	q->next = t;
}

取最值

链表取最值
LNode *p,*q;
int max = head->next->data;
q = p = head->next;
while(p!=NULL){
	if(max < p->data){
		max = p->data;
		q = p;
	}
	p = p->next;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

Black_Me_Bo

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

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

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

打赏作者

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

抵扣说明:

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

余额充值