前言:从学习数据结构与算法开始,总感觉自己的理解是狭隘的。对于很多的知识点都只是了解,不曾深入探讨,导致现在一直在一个较低的水平。古人常说“纸上得来终觉浅,绝知此事要躬行”,我也明白先天的不足是要通过后天的努力修补。但是因为懒做的原因,我便一直拖延,但像这种在学校学习的时间的确所剩无几。故借此来提醒自己刻苦用功,以求能更上层楼。在下一直坚信这不只是一个人在战斗,更希望借此机会抛砖引玉,再开见闻。
线性表
一.定义:
可以这样说,线性表是零个或者n 个数据元素的有限序列。
二.表达方式:
一般指的是在计算机的存储结构,这里有顺序存储与链式存储。
1.顺序表达
原理是数组的顺序存储结构。
来看下代码
#define N 100
struct s
{
int data[N];
int length;//用来显示长度多少
};
以上的代码是顺序存储的结构,其中的部分代码可以依仗需求来更改
2.顺序存储的插入与删除
(主要理解这两个就没有什么大问题)
插入:
void Insert(struct s *p,int k,int e)//后两者是要插入的位置k与插入的数据m
{
int j;
if(p->length==Max)//表示顺序表已经满了
exit(0);
if (k<1||k>p->length+1)//表示选择插入的位置不对
exit(0);
if(k<=p->length)//可以插入
{
for(j=p->length-1;j>=k-1;j--)//元素后移
p->data[j+1]=p->data[j];
}
p->data[k-1]=e;
p->length++;
}
删除:
void Del(struct list *q,int k)
{
int j;
if(q->length==0)//表示顺序表是空的,没法删
exit(0);
if(k<1||k>q->length)//同插入一样,表示删除的位置不对
exit(0);
if(k<q->length)
{
for(j=k;j<q->length;j++)//元素前移
{
q->data[j-1]=q->data[j];
}
}
q->length--;
}
完整的表达式:
#include <iostream>
#define Max 103
using namespace std;
struct list
{
int data[Max];
int length;
};
void Insert(struct list *p,int k,int e)//插入
{
int j;
if(p->length==Max)
exit(0);
if (k<1||k>p->length+1)
exit(0);
if(k<=p->length)
{
for(j=p->length-1;j>=k-1;j--)
p->data[j+1]=p->data[j];
}
p->data[k-1]=e;
p->length++;
}
void Del(struct list *q,int k)//删除
{
int j;
if(q->length==0)
exit(0);
if(k<1||k>q->length)
exit(0);
if(k<q->length)
{
for(j=k;j<q->length;j++)
{
q->data[j-1]=q->data[j];
}
}
q->length--;
}
int main()
{
struct list s;
s.length=0;
int n,m,j,k1,l,i;
cin>>n;
for(i=0;i<n;i++)
{
cin>>s.data[i];
s.length++;
}
cout<<"输入插入的数与位置"<<endl;
cin>>m>>l;
Inset(&s,l,m);
for(i=0;i<s.length;i++)
{
cout<<s.data[i]<<" ";
}
cout<<endl;
cout<<"输入要删除的位置"<<endl;
cin>>k1;
Del(&s,k1);
for(i=0;i<s.length;i++)
{
cout<<s.data[i]<<" ";
}
return 0;
}
3.链式表达
原理主要是运用指针
个人在这里用时会开出头节点,用起来方便些
struct node
{
int data;//数据域
struct node *next;//指向下一节点的指针域
};
4.链表的插入与删除
同顺序的要点,我们来看
注:链表的插入一共有两种,分别是头插与尾插
1.头插入:
void Front_Insert(struct node *L,int k)//头插
{
struct node *p;//建立新节点
int i,m;
for(i=0;i<k;i++)
{
cin>>m;
p=new(struct node);
p->data=m;//将输入的值赋值给节点p
p->next=L->next;//将头结点的指针赋值给p节点
L->next=p;//L节点指向p
}
}
2.尾插入:
void End_Insert(struct node *L,int k)//尾插
{
struct node *q,*r;//建立新节点
r=L;//头结点赋值与r,这样r就具有头结点的性质
int i,m;
for(i=0;i<k;i++)
{
cin>>m;
q=new(struct node);
q->data=m;将输入的值赋值给节点q
r->next=q;//r结点指向q节点
r=q;//令r接点等于q接点
}
r->next=NULL;//最后将最后一节点的指针置空
}
删除:
这个就没有那么绕了,就是将节点断开并释放的意思
C++中用new来创建动态空间,用delete来释放空间
void Del(struct node *L,int k)
{
int j=1;
struct node *p,*q;//建立新节点
p=L;
while(p->next&&j<k)//首先先遍历要删除节点之前的所有节点,即k-1;
{
p=p->next;
j++;
}
if(!(p->next)||j<k)//如果没找到节点,就结束了
exit(0);
q=p->next;//将p节点的下一个节点赋值给q节点
p->next=q->next;//将q节点指向的节点赋值给p节点
delete(q);//释放q节点
}
链表的完全代码:
#include <iostream>
using namespace std;
struct node
{
int data;
struct node *next;
};
void Front_Insert(struct node *L,int k)//头插
{
struct node *p;//建立新节点
int i,m;
for(i=0;i<k;i++)
{
cin>>m;
p=new(struct node);
p->data=m;//将输入的值赋值给节点p
p->next=L->next;//将头结点的指针赋值给p节点
L->next=p;//L节点指向p
}
}
void End_Insert(struct node *L,int k)//尾插
{
struct node *q,*r;//建立新节点
r=L;//头结点赋值与r,这样r就具有头结点的性质
int i,m;
for(i=0;i<k;i++)
{
cin>>m;
q=new(struct node);
q->data=m;将输入的值赋值给节点q
r->next=q;//r结点指向q节点
r=q;//令r接点等于q接点
}
r->next=NULL;//最后将最后一节点的指针置空
}
void Del(struct node *L,int k)
{
int j=1;
struct node *p,*q;//建立新节点
p=L;
while(p->next&&j<k)//首先先遍历要删除节点之前的所有节点,即k-1;
{
p=p->next;
j++;
}
if(!(p->next)||j<k)//如果没找到节点,就结束了
exit(0);
q=p->next;//将p节点的下一个节点赋值给q节点
p->next=q->next;//将q节点指向的节点赋值给p节点
delete(q);//释放q节点
}
int main()
{
struct node s;
s.next=NULL;//将初始化的链表置空
int n,k,i;
cin>>n;
Front_Insert(&s,n);//头插
//End_Insert(&s,n);//尾插
cout<<"输入要删除的节点"<<endl;
cin>>k;
Del(&s,k);
struct node *q;//输出
q->next=s.next;
while(q->next!=NULL)
{
q=q->next;
cout<<q->data<<" ";
}
return 0;
}
后记
写到这里,顺序表最基本的两种形式算是画上了一个‘,’,还有这两种表的其他操作与其他的线性表,这里就不做太多表述。笔者在写这篇时,借助了书中的大部分思想,在这里借鉴的是《大话数据结构》与清华大学出版的《数据结构(c语言版)》,这两本书可以说是笔者数据结构的启蒙书。如果有其他的优秀书籍,还请读者不吝赐教。若有不足之处,还请指出。