线性表
学习视频:来自于天勤考研
本文主要代码是使用的c++
1.逻辑结构
线性表是具有相同特性
数据元素的有限序列
。
相同特性:把同一类事物归类,方便批量处理
。
有限:表中元素个数为n,n有限大
,n可以为0。
序列:表中元素排成一列,体现了一对一的逻辑特性
(每个元素有则仅有一个前驱和一个后继)。
2.存储结构
存储结构分为顺序存储结构
和链式存储结构
。
1.顺序存储和链式存储的区别:
性能 | 具体功能 | 顺序存储 | 链式存储 |
---|---|---|---|
空间性能 | 存储分配 | 一次性分配 | 动态分配(优) |
空间性能 | 存储密度 (下面会有解释) | =1(优) | <1 |
时间性能 | 查找 | O((n+1)/2) | O(n/2) |
时间性能 | 读运算 | O(1)(优) | O((n+1)/2) 最好情况为1,最坏情况为n |
时间性能 | 插入运算 (性能主要指 需要移动元素个数 ) | O(n/2)最好 最好情况为0,最坏情况为n | O(1),更优 |
时间性能 | 删除运算 | O((n-1)/2) 最好情况为0,最坏情况为n-1 | O(1),更优 |
结论:
从表整体来看,一般顺序表存储空间利用率低于链表。
从单个存储单元来看,顺序存储空间利用率高于链表。
2.存储密度
存储密度=结点值域类所占的存储量/结点结构所占的存储总量
。
顺序存储:只有数据,没有其他东西,所以数据所占的存储密度为1
。
链式存储:除了数据,还有结点,所以数据所占的存储密度小于1。
关于为什么存储密度越小它就更优呢?
因为顺序存储的存储密度为1,所以相同的内存,顺序存储存储的数据比链式存储多
,所以顺序存储更优。
3.链式存储结构
1.单链表
结点类型定义:
带头结点(比较好用):
不带头结点(缺点,当链表为空时,需要重新写一部分代码):
2.双链表
结点类型定义:
带头结点:
不带头结点:
3.循环链表
带头结点的单循环链表和循环链表:
不带头结点的单循环链表和双循环链表:
4.静态链表
静态链表的增删改查操作:https://blog.csdn.net/qq_45137584/article/details/116567741
结点类型定义:
特点:一次性分配所有内存
。
4.线性表的代码实现
1.顺序存储结构
顺序存储结构我们比较常见,所以实现起来还是比较熟悉的。
1.建表
#include<bits/stdc++.h>
using namespace std;
#define maxSize 100
//建表
int createList(int A[],int &length){
if(length>maxSize)
return 0;
for(int i=0;i<length;++i)
cin>>A[i];
return 1;
}
int main(){
int A[maxSize];
int length;
cin>>length;
createList(A,length);
for(int i=0;i<length;i++){
cout<<A[i]<<" ";
}
return 0;
}
效果:
2.转置
#include<bits/stdc++.h>
using namespace std;
#define maxSize 100
int createList(int A[],int &length){
if(length>maxSize)
return 0;
for(int i=0;i<length;++i)
cin>>A[i];
return 1;
}
//转置代码
void Transpose(int a[],int length)
{
int temp;
for(int i=0,j=length-1;i<j;i++,j--){
temp=a[i];
a[i]=a[j];
a[j]=temp;
}
}
int main(){
int A[maxSize];
int length;
cin>>length;
createList(A,length);
for(int i=0;i<length;i++){
cout<<A[i]<<" ";
}
cout<<endl;
Transpose(A,length);
for(int i=0;i<length;i++){
cout<<A[i]<<" ";
}
return 0;
}
结果:
3.求最值
#include<bits/stdc++.h>
using namespace std;
#define maxSize 100
int createList(int A[],int &length){
if(length>maxSize)
return 0;
for(int i=0;i<length;++i)
cin>>A[i];
return 1;
}
//求最值
int maxData(int a[],int length){
int max=a[0];
int maxIdx=0;
for(int i=0;i<length;++i){
if(max<a[i]){
max=a[i];
maxIdx=i;
}
}
return max;
}
int main(){
int A[maxSize];
int length;
cin>>length;
createList(A,length);
cout<<maxData(A,length);
return 0;
}
4.划分
主要功能是:首先确定第一个数为划分点,然后通过i,j指向第一个元素和最后一个元素来比较,实现划分点前的数值一定小于它,划分点后的数一定大于它
。
#include<bits/stdc++.h>
using namespace std;
#define maxSize 100
int createList(int A[],int &length){
if(length>maxSize)
return 0;
for(int i=0;i<length;++i)
cin>>A[i];
return 1;
}
int maxData(int a[],int length){
int max=a[0];
int maxIdx=0;
for(int i=0;i<length;++i){
if(max<a[i]){
max=a[i];
maxIdx=i;
}
}
return max;
}
void partition(int arr[],int n){
int temp;
int i=0,j=n-1;
temp=arr[i];
while(i<j)
{
while(i<j&&arr[j]>=temp)
--j;
if(i<j)
{
arr[i]=arr[j];
++i;
}
while(i<j&&arr[i]<temp)
++i;
if(i<j)
{
arr[j]=arr[i];
--j;
}
arr[i]=temp;
}
}
int main(){
int A[maxSize];
int length;
cin>>length;
createList(A,length);
partition(A,length);
for(int i=0;i<length;i++)
cout<<A[i]<<" ";
cout<<endl;
return 0;
}
5.归并
主要功能:将两个数组按照大小排序放入同一个数组
。
#include<bits/stdc++.h>
using namespace std;
#define maxSize 100
int createList(int A[],int &length){
if(length>maxSize)
return 0;
for(int i=0;i<length;++i)
cin>>A[i];
return 1;
}
//归并
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++];
else
c[k++]=b[j++];
}
while(i<m)
c[k++]=a[i++];
while(j<n)
c[k++]=b[j++];
}
int main(){
int A[maxSize];
int B[maxSize];
int C[maxSize];
int length,length1;
cin>>length;
createList(A,length);
cin>>length1;
createList(B,length1);
mergearray(A,length,B,length1,C);
for(int i=0;i<length+length1;i++){
cout<<C[i]<<" ";
}
cout<<endl;
return 0;
}
2.链式存储结构
1.建表
如果你是使用c语言的话,需要用p=(LNode*)malloc(sizeof(LNode));这种形式来申请内存
,但是如果你是用于c++的话,当然你也可以使用c语言的方法来申请内存,但是你可以使用p=new LNode();这种方法来申请内存
,使用起来更简单方便,其中LNode()为你定义的结构体名字
,和java有点相似。
如果你是其他类型的数据,把int类型改为你需要的类型就行了。
尾插法
#include <bits/stdc++.h>
using namespace std;
typedef struct LNode
{
int data;
struct LNode *next;
}LNode;
//尾插法
void createLinkListR(LNode *&head){
head->next=NULL;
LNode *p=NULL,*r=head;
int n;
cin>>n;
for(int i=0;i<n;++i){
p=new LNode();
p->next=NULL;
cin>>p->data;
//这里主要针对于单链表
p->next=r->next;
r->next=p;
r=p;
}
}
int main(){
LNode *head=new LNode();
createLinkListR(head);
for(LNode *r=head;r->next!=NULL;r=r->next){
cout<<r->next->data<<" ";
}
return 0;
}
效果:
头插法
#include<bits/stdc++.h>
using namespace std;
typedef struct LNode{
int data;
struct LNode *next;
}LNode;
void createLinkListH(LNode *&head){
head->next=NULL;
LNode *p=NULL;
int n;
cin>>n;
for(int i=0;i<n;++i)
{
p=new LNode();
p->next=NULL;
cin>>p->data;
p->next=head->next;
head->next=p;
}
}
int main(){
LNode *head=new LNode();
createLinkListH(head);
for(LNode *r=head;r->next!=NULL;r=r->next){
cout<<r->next->data<<" ";
}
return 0;
}
可以从下面效果看出我们存储的数据与我们输入的数据的相反的。
效果:
2.转置
#include <bits/stdc++.h>
using namespace std;
typedef struct LNode
{
int data;
struct LNode *next;
}LNode;
//尾插法
void createLinkListR(LNode *&head,LNode *&r){
head->next=NULL;
LNode *p=NULL;
r=head;
int n;
cin>>n;
for(int i=0;i<n;++i){
p=new LNode();
p->next=NULL;
cin>>p->data;
p->next=r->next;
r->next=p;
r=p;
}
}
//转置代码
void Transpose(LNode *&p,LNode *&q){
LNode *t=NULL;
while(p->next!=q){
t=p->next;
p->next=t->next;
t->next=q->next;
q->next=t;
}
}
int main(){
LNode *head=new LNode();
LNode *r;
createLinkListR(head,r);
for(LNode *r=head;r->next!=NULL;r=r->next){
cout<<r->next->data<<" ";
}
cout<<endl;
Transpose(head,r);
for(LNode *r=head;r->next!=NULL;r=r->next){
cout<<r->next->data<<" ";
}
return 0;
}
结果:
3.求最值
#include <bits/stdc++.h>
using namespace std;
typedef struct LNode
{
int data;
struct LNode *next;
}LNode;
//尾插法
void createLinkListR(LNode *&head,LNode *&r){
head->next=NULL;
LNode *p=NULL;
r=head;
int n;
cin>>n;
for(int i=0;i<n;++i){
p=new LNode();
p->next=NULL;
cin>>p->data;
p->next=r->next;
r->next=p;
r=p;
}
}
int maxData(LNode *head){
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;
}
return q->data;
}
int main(){
LNode *head=new LNode();
LNode *r;
createLinkListR(head,r);
cout<<maxData(head)<<endl;
return 0;
}
4.归并
#include <bits/stdc++.h>
using namespace std;
typedef struct LNode
{
int data;
struct LNode *next;
}LNode;
//尾插法
void createLinkListR(LNode *&head,LNode *&r){
head->next=NULL;
LNode *p=NULL;
r=head;
int n;
cin>>n;
for(int i=0;i<n;++i){
p=new LNode();
p->next=NULL;
cin>>p->data;
p->next=r->next;
r->next=p;
r=p;
}
}
//归并
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(q!=NULL)
r->next=q;
}
int main(){
LNode *A=new LNode();
LNode *B=new LNode();
LNode *C;
LNode *r;
LNode *q;
createLinkListR(A,r);
createLinkListR(B,q);
merge(A,B,C);
for(LNode *r=C;r->next!=NULL;r=r->next)
{
cout<<r->next->data<<" ";
}
return 0;
}
下面这题是不含头结点的合并
剑指 Offer 25. 合并两个排序的链表
输入两个递增排序的链表,合并这两个链表并使新链表中的节点仍然是递增排序的。
示例1:
输入:1->2->4, 1->3->4
输出:1->1->2->3->4->4
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
ListNode* mergeTwoLists(ListNode* l1, ListNode* l2) {
ListNode *p=l1;ListNode *q=l2;
ListNode *r,*head;
if(p!=NULL&&q!=NULL){
if(p->val<=q->val){
head=p;
p=p->next;
}else{
head=q;
q=q->next;
}
r=head;
while(p!=NULL&&q!=NULL)
{
if(p->val<=q->val)
{
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;
}else{
r->next=q;
}
}else if(p!=NULL||q!=NULL){
if(p!=NULL){
head=p;
}else{
head=q;
}
}
else{
head=NULL;
}
return head;
}
};