线性表的定义
线性表是一种最简单的线性结构,一个线性表是n个数据元素的有序序列。
同一线性表中的元素必定具有相同特性,就是要属于同一数据对象,相邻数据元素之间存在着序偶关系(序偶:一对有序的数)
在一个线性表中,一个数据元素可以由若干个数据项组成。在这种情况下,常把数据元素称为记录,含有大量元素的线性表又叫文件。
MOOC上是:
线性表:由同类型数据元素构成有序序列的线性结构
表中元素个数称为线性表的长度
线性表没有元素时,称为空表
表起始位置称表头,表结束位置称表尾
【线性结构是一个数据元素的有序集
它的特点是:
- 存在唯一一个被称作“第一个”的数据元素
- 存在唯一一个被称作“最后一个”的数据元素
- 除第一个外,集合中的每个数据元素均只有一个前驱
- 除最后一个外,集合中每个数据元素均只有一个后继
】
线性表的顺序表示和实现
线性表的顺序表示指的是用一组地址连续的存储单元依次存储线性表的数据元素。【缺点在于插入或删除元素的时候需要移动大量元素】
初始化、插入、删除、查找、合并、尾插、长度、判断空、销毁、打印、清空
//线性表的顺序存储
#include<cstdio>
#include<iostream>
#include<stdlib.h>
#define SIZE 100
typedef char Elemtype;
typedef int Status;
using namespace std;
typedef struct{
Elemtype* elem;//存放线性表地址
int length;//存放长度
int listsize;//当前分配的存储容量
}Sqlist;//结构体变量名
Status InitList(Sqlist &L)//初始化
{
L.elem=(Elemtype *)malloc(SIZE*sizeof(Elemtype));
if(!L.elem)
exit(0);
L.length=0;
L.listsize=SIZE;
return 1;
}
Status Listinsert(Sqlist &L,int i,Elemtype e)//在第i个位置之前插入新元素e
{
Elemtype *newbase,*q,*s;
if(i>L.length+1||i<1)
return 0;
if(L.length>=L.listsize){
newbase=(Elemtype*)realloc(L.elem,(L.listsize+SIZE)*sizeof(Elemtype));
if(!newbase)
exit(0);
L.elem=newbase;
L.listsize+=SIZE;
}
q=&(L.elem[i-1]);
for(s=&(L.elem[L.length-1]);s>=q;--s)
{
*(s+1)=*s;
}
*q=e;
++L.length;
return 1;
}
//删除第i个元素,并用e返回这个值
Status Listdelect(Sqlist &L,int i,Elemtype &e){
if(i<1||i>L.length)
return 0;
e=L.elem[i-1];
for(int j=i;j<L.length;j++)
L.elem[j-1]=L.elem[j];
L.length--;
return 1;
}
//按照位置取元素
void Getelem(Sqlist &L,int i,Elemtype &e){
e=L.elem[i-1];
}
//长度
Status Listlength(Sqlist &L)
{
return L.length;
}
//尾插
Status Pushback(Sqlist &L,Elemtype e){
Elemtype *newbase;
if(L.length>=L.listsize){
newbase=(Elemtype*)realloc(L.elem,(L.listsize+SIZE)*sizeof(Elemtype));
if(!newbase)
exit(0);
L.elem=newbase;
L.listsize+=SIZE;
}
L.elem[L.length]=e;
++L.length;
return 1;
}
//判断空
void isempty(Sqlist &L)
{
if(L.length==0)
printf("该表空\n");
else
printf("该表不空\n");
}
//销毁顺序表
void Destroy(Sqlist &L)
{
free(L.elem);
}
//打印内容
void Dislist(Sqlist &L){
printf("该顺序表的元素为:");
for(int i=0;i<L.length;i++)
printf("%c ",L.elem[i]);
printf("\n");
}
//清空
Status Clear(Sqlist &L){
L.length=0;
printf("清空!");
return 1;
}
int main()
{
Sqlist L;
InitList(L);
isempty(L);
Elemtype e;
Pushback(L,'a');
Pushback(L,'b');
Pushback(L,'c');
Pushback(L,'d');
Pushback(L,'e');
Dislist(L);
printf("该表长度为:%d\n",Listlength(L));
Getelem(L,4,e);
printf("该顺序表的第4个元素为%c\n",e);
printf("在第三个位置前上插入元素h\n");
Listinsert(L,3,'h');
Dislist(L);
printf("在第四个位置前插入元素m\n");
Listinsert(L,4,'m');
Dislist(L);
Listdelect(L,6,e);
printf("删除第六个元素,该元素为%c\n",e);
return 0;
}
结果:
合并两个表
//将所有在线性表Lb中但不在La中的数据元素插入到La中
void Union1(Sqlist &L1,Sqlist &L2)
{
int i,j;
int flag;//判断两个值是否相同
int len1,len2;
len1=Listlength(L1);
len2=Listlength(L2);
for(i=0;i<=len2;i++){
flag=1;
for(j=0;j<=len1;j++){
if(L1.elem[j]==L2.elem[i])
flag=0;
if(flag)
{
++L1.length;
L1.elem[L1.length-1]=L2.elem[i];
}
}
}
}
void Union2(Sqlist &L1,Sqlist &L2){
}//先暂时放一下,以后再补p20
void MergeList(Sqlist &L1,Sqlist &L2,SqList &L3){
//已知顺序线性表L1,L2的元素按值非递减排序
//归并L1,L2得到新的顺序线性表L3,L3的元素也按值非递减排列
}//p26
顺序表的特点
逻辑上相邻的元素,物理位置也相邻
可随机访问表中元素
顺序表的存储空间不易扩充,易造成存储空间的利用率低
做插入和删除操作的时候需要移动大量元素,效率不高
线性表的链式表示和实现
线性表的链式存储结构的特点是用一组任意的存储单元存储线性表的数据元素。(单链表)
单链表的基本操作:插入、删除……
//线性表的单链表
#include<cstdio>
#include<iostream>
#include<stdlib.h>
#define Elemtype char
using namespace std;
typedef struct Node{
Elemtype data;
struct Node *next;
}Node,*SqList;
void InitList(SqList &L){
L=(SqList)malloc(sizeof(SqList));
L->next=NULL;
}
//尾插法
void createlist(SqList &L, char a[], int n)
{
Node *s,*r;
int i;
L = (SqList)malloc(sizeof(Node));
L -> next = NULL;
r = L;
for(i=0;i<n;++i)
{
s = (Node*)malloc(sizeof(Node));
s ->data = a[i];
r ->next = s;
r = r ->next;
}
r ->next = NULL;
}
int ListInsert(SqList &L,int i,Elemtype e){
Node *p;
p=L;
int j=1;
while(p&&j<i)
{
p=p->next;
++j;
}
if(!p||j>i)
return 0;
Node *s;
s=(Node *)malloc(sizeof(Node));
s->data=e;
s->next=p->next;
p->next=s;
return 1;
}
void DispList(SqList &L)
{
Node *p=L->next;
while(p!=NULL)
{
printf("%c ",p->data);
p=p->next;
}
printf("\n");
}
int ListLength(SqList &L)
{
int i=-1;
Node *head;
head=L;
while(head!=NULL)
{
head=head->next;
i++;
}
return i;
}
int ListEmpty(SqList &L)
{
return L->next!=NULL;
}
int Getelem(SqList &L,int i)
{
Node *p;
p=L->next;
int j=1;
while(p!=NULL&&j<i)
{
p=p->next;
j++;
}
if(!p||j>i)
return 0;
char e=p->data;
return e;
}
bool LocateElem(SqList &L,Elemtype e)
{
Node *p;
p=L->next;
while(p&&p->data!=e)
p=p->next;
if(!p)
return false;
return true;
}
void DestroyList(SqList &L)
{
Node *p;
while(L!=NULL)
{
p=L;
L=L->next;
free(p);
}
}
int ListDelete(SqList &L,int i)
{
Node *p;
p=L;
int j=1;
while(p->next&&j<i)
{
p=p->next;
j++;
}
if(!(p->next)||j>i)
return 0;
Node *q;
q=p->next;
p->next=q->next;
char e=q->data;
free(q);
return e;
}
int main()
{
SqList L;//L为单链表的头指针,它指向表中的第一个结点,若L为空(L==NULL),则所表示的线性表为空表,其长度n为0
printf("初始化单链表L\n");
InitList(L);
printf("依次采用尾插法插入a,b,c,d,e元素\n");
char a[5]={'a','b','c','d','e'};
createlist(L,a,5);
printf("输出单链表L:");
DispList(L);
printf("输出单链表L的长度:");
printf("%d",ListLength(L));
printf("\n");
printf("判断单链表L是否为空\n");
if(ListEmpty(L)==0)
printf("空\n");
else
printf("非空\n");
printf("单链表L的第3个元素=%c\n",Getelem(L,3));
printf("输出元素a的位置\n");
printf("%d",LocateElem(L,'a'));
printf("\n");
printf("在第4个元素位置上插入f元素\n");
ListInsert(L,4,'f');
printf("输出单链表L:");
DispList(L);
printf("删除L的第3个元素\n");
ListDelete(L,3);
printf("输出单链表L\n");
DispList(L);
printf("释放单链表L\n");
DestroyList(L);
return 0;
}
结果:
合并两个有序链表
void MergeList(SqList &La,SqList &Lb,SqList &Lc){
//已知单链线性表La和Lb的元素按值非递减排序
//归并La和Lb得到新的单链线性表Lc,Lc的元素也按值非递减排列
Node *pa;
pa=La->next;
Node *pb;
pb=Lb->next;
Node *pc;
pc=La;
Lc=pc;
while(pa&&pb){
if(pa->data<=pb->data){
pc->next=pa;
pc=pa;
pa=pa->next;
}
else{
pc->next=pb;
pc=pb;
pb=pb->next;
}
}
pc->next=pa?pa:pb;//插入剩余段
free(Lb);
}
}
int main()
{
SqList La,Lb,Lc;
printf("初始化单链表La,Lb,Lc\n");
InitList(La);
InitList(Lb);
InitList(Lc);
printf("依次采用尾插法插入1,2,3,4,5元素\n");
char a[5]={1,2,3,4,5};
createlist(La,a,5);
printf("依次采用尾插法插入2,3,4,6,7元素\n");
char b[5]={2,3,4,6,7};
createlist(Lb,b,5);
printf("归并La和Lb得到新的单链线性表Lc\n");
MergeList(La,Lb,Lc);
printf("输出单链表Lc:");
DispList(Lc);
return 0;
}
线性链表(单链表)
线性表的链式存储结构的特点是用一组任意的存储单元存储线性表的数据元素。
以元素(数据元素的映像)+指针(指示后级元素存储位置)=结点来表示线性表
又由于此链表中的每个结点中只包含一个指针域,所以称为线性链表或单链表
以线性表中第一个数据元素a1的存储地址作为线性表的地址,称作线性表的头指针。
有时为了操作方便,在第一个结点之前虚加一个“头结点”,以指向头结点的指针为链表的头指针。
单链表是一种顺序存取的结构(如果想要找到第i个元素,就必须要先找到第i-1个元素)
如何从线性表得到单链表?
链表是一个动态的结构,它不需要分配空间,因此生成链表的过程是一个结点“逐个插入”的过程
一个带头结点的线性链表类型
typedef struct LNode{//结点类型
ElemType data;
struct LNode *next;
}*Link,*Position;
typedef struct{//链表类型
Link head,tail;//分别指向线性链表中的头结点和最后一个结点
int len;//指示线性链表中数据元素的个数
}LinkList;
静态单链表
用一维数组来描述线性链表
typedef struct{
ElemType data;
int cur;
}component,SLinkList[MAX];
循环链表
表中的最后一个结点的指针域指向头结点,整个链表形成一个环
双向链表
在双向链表的结点中有两个指针域,其一指向直接后继,另一指向直接前驱。
typedef struct Node{
Elemtype data;
struct Node *prior;
struct Node *next;
}Node,*Linklist;