目录
线性表(List)是由n个形同类型的数据元素构成的有限序列。记为:L=(a1,a2,···,ai,···,an),将ai-1称为ai的直接前驱,将ai+1称为ai的直接后继。
线性表的形式化定义:线性表(List)简记为L,是一个二元组,L=(D,R),D是数据元素的有限集合,R是数据元素之间关系的有限集合。
Linear_List=(D, S )
D={ ai | ai∈elemset,1≤i≤n}
S={ 〈ai,ai+1〉 | 1≤i≤n−1 }
线性表的特征:
1)对非空表,a0是表头,无前驱;
2)an-1是表尾,无后继;
3)其他的每个元素ai有且仅有一个直接前驱ai-1和一个直接后继ai+1。
线性表的顺序存储(顺序表)
last代表最后一个元素的下表,最大是N-1。
线性表的顺序存储缺点:
线性表的顺序存储结构有存储密度高以及能够随机存取等优点,但存在以下不足:
(1) 要求系统提供一片较大的连续存储空间。
(2) 插入、删除等运算耗时,且存在元素在存储区域内成片移动的现象。
线性表常用代码
sqlist.c(相关函数的实现)
#include "sqlist.h"
/*
建立一个线性表
*/
sqlink list_create()
{
sqlink L;
L=(sqlink)malloc(sizeof(sqlist));
if(L==NULL)
printf("malloc failed\n");
memset(L,0,sizeof(sqlist));
L->last=-1; //last=-1代表线性表为空
return L;
}
/*
删除线性表
*/
int list_free(sqlink L)
{
if(L==NULL)
return -1;
free(L);
L=NULL;
return 0;
}
/*
清空线性表
*/
int list_clear(sqlink L)
{
if(L==NULL)
return -1;//如果传入的是空表,返回-1
memset(L,0,sizeof(sqlist));
L->last=-1;
return 0; //成功之后返回0
}
/*
检查线性表是否为空,空返回1,非空返回0
*/
int list_empty(sqlink L)
{
if(L->last==-1)
return 1;
else
return 0;
}
/*
求线性表的长度
*/
int list_length(sqlink L)
{
if(L==NULL)
return -1;
return(L->last+1);
}
/*
看value是否在L中,有就返回pos,无就返回-1
*/
int list_locate(sqlink L,data_t value)
{
int i;
for(i=0;i<=L->last;i++)
{
if(L->data[i]==value)
return i;
}
return -1;
}
/*
插入数据到线性表
*/
int list_insert(sqlink L,data_t value,int pos)
{
int i;
if(L->last==N-1)
{
printf("List Is Full\n");
return -1;
}
if(pos<0||pos>L->last+1)
{
printf("pos is invaild\n");
return -1;
}
for(i=L->last;i>=pos;i--)//如果让i=pos,i++的话会导致最后一个元素再往后移动的过程中丢失
{
L->data[i+1]=L->data[i];
}
L->data[pos]=value;
L->last++;
return 0;
}
/*
删除掉指定位置的数据
*/
int list_delete(sqlink L,int pos)
{
int i;
if(L->last==-1)
{
printf("it is empty");
return -1;
}
if(pos<0||pos>L->last)
{
printf("pos is invaild\n");
return -1;
}
for(i=pos;i<L->last;i++)
{
L->data[i]=L->data[i+1];
}
L->last--;
return 0;
}
/*
合并两个线性表
*/
int list_merge(sqlink L1,sqlink L2)
{
int i=0;
int ret;
for(i=0;i<=L2->last;i++)
{
ret=list_locate(L1,L2->data[i]);
if(ret==-1)//ret=-1代表L1中没有这个元素
{
if(list_insert(L1,L2->data[i],L1->last+1)==-1)
return -1;//L1内存溢出,返回-1
}
}
return 0;
}
/*
删除线性表中的重复元素
*/
int list_purge(sqlink L)
{
int i=1;
int j;
if(L->last==0)
return 0;
while(i<=L->last)
{
j=i-1;
while(j>=0)
{
if(L->data[i]==L->data[j])
{
list_delete(L,i);
break;
}
else
j--;
}
if(j<0)
{
i++;
}
}
return 0;
}
/*
遍历线性表,打印所有元素
*/
int list_show(sqlink L)
{
int i;
if(L==NULL)
return -1;
if(L->last==-1)
printf("List is empty\n");
for(i=0;i<=L->last;i++)
{
printf("%d\n",L->data[i]);
}
return 0;
}
sqlist.h(头文件)
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define N 128
typedef int data_t;
struct sqlist_t
{
data_t data[N];
int last;
};
typedef struct sqlist_t sqlist;
typedef struct sqlist_t* sqlink;
sqlink list_create();
int list_free(sqlink L);
int list_clear(sqlink L);
int list_empty(sqlink L);
int list_length(sqlink L);
int list_locate(sqlink L,data_t value);
int list_insert(sqlink L,data_t value,int pos);
int list_delete(sqlink L,int pos);
int list_merge(sqlink L1,sqlink L2);
int list_purge(sqlink L);
int list_show(sqlink L);
/*typedef struct {
data_t data[N];
int last;
}sqlist, *sqlink;*/
test.c(测试代码)
#include "sqlist.h"
void test_insert();
void test_delete();
void test_merge();
void test_purge();
int main()
{
//test_insert();
//test_delete();
//test_merge();
test_purge();
return 0;
}
void test_insert()
{
sqlink L1;
L1=list_create();
list_insert(L1,10,0);
list_insert(L1,20,0);
list_insert(L1,30,0);
list_insert(L1,40,0);
list_insert(L1,50,0);
list_insert(L1,60,0);
list_show(L1);
}
void test_delete()
{
sqlink L1;
L1=list_create();
list_insert(L1,10,0);
list_insert(L1,20,0);
list_insert(L1,30,0);
list_insert(L1,40,0);
list_insert(L1,50,0);
list_insert(L1,60,0);
list_delete(L1,3);
list_show(L1);
}
void test_merge()
{
sqlink L1;
sqlink L2;
L1=list_create();
L2=list_create();
list_insert(L1,10,0);
list_insert(L1,20,0);
list_insert(L1,30,0);
list_insert(L1,40,0);
list_insert(L1,50,0);
list_insert(L1,60,0);
list_insert(L2,90,0);
list_insert(L2,60,0);
list_insert(L2,100,0);
list_insert(L2,00,0);
list_insert(L2,80,0);
list_insert(L2,70,0);
list_show(L1);
list_show(L2);
list_merge(L1,L2);
list_show(L1);
}
void test_purge()
{
sqlink L1;
L1=list_create();
list_insert(L1,10,0);
list_insert(L1,10,0);
list_insert(L1,20,0);
list_insert(L1,10,0);
list_insert(L1,10,0);
list_insert(L1,10,0);
list_show(L1);
printf("\n\n\n");
list_purge(L1);
list_show(L1);
}
线性表的链式存储(重点)
线性表的链式存储结构:将线性表L=(a0,a1..an-1)中各元素分布在存储器中的不同存储块,称为结点,通过地址或指针建立元素之间的联系。
结点的data区域存放数据元素ai,而next域是一个指针,指向后继ai+1所在的结点。
malloc申请的内存在堆上,例如(linklist)malloc(sizeof(linklist)),指针初始化后存放在栈上,例如listnode A,linklist p=&A。动态申请内存时常用malloc。
链式表常用代码
linklist.c(常用函数的实现)
#include "linklist.h"
linklist list_create()
{
linklist H;
H=(linklist)malloc(sizeof(listnode));
if(H==NULL)
printf("malloc failed\n");
H->data=0;
H->next=NULL;
return H;
}
int list_tail_insert(linklist H,data_t value)//head
{
linklist p;//1、创建一个新结点承接value
linklist q;
if(H==NULL)
{
printf("H is NULL\n");
return -1;
}
if((p=(linklist)malloc(sizeof(listnode)))==NULL)
{
printf("malloc failed\n");
return -1;
}
p->data=value;
p->next=NULL;
q=H;
while(q->next!=NULL)//2、找到尾部结点
{
q=q->next;
}
q->next=p;//3、插入结点
return 0;
}
/*
链表的按序号查找,拿到pos位置的指针
*/
linklist list_get(linklist H,int pos)
{
linklist p=H;
int i=0;
if(p==NULL)
{
printf("H is NULL\n");
return NULL;
}
if(pos==-1)//类似于顺序表,将头设置为-1
{
return p;
}
if(pos<-1)
{
printf("pos is invalid\n");
return NULL;
}
while(i<=pos)//加等于号是因为要从头结点(头结点并不一定是首元结点)开始查找
{
p=p->next;
if(p==NULL)//防止pos太大,造成段错误
{
printf("pos is invaild\n");
return NULL;
}
i++;
}
return p;
}
/*
将新结点插入到pos后面
*/
int list_insert(linklist H,data_t value,int pos)
{
linklist p;
linklist q;
p=list_get(H,pos-1);
if(p==NULL)
{
printf("p is NULL\n");
return -1;
}
if((q=(linklist)malloc(sizeof(listnode)))==NULL)
{
printf("malloc failed\n");
return -1;
}
q->data=value;
q->next=NULL;
q->next=p->next;//一定要先把新结点指针改掉,再去改前面节点的指针
p->next=q;
return 0;
}
/*
删除掉pos处的结点
*/
int list_delete(linklist H,int pos)
{
linklist p;
if(H==NULL)
{
printf("H is NULL\n");
return -1;
}
p=list_get(H,pos-1);//找到要删除结点的前驱
linklist q=p->next;
if(p==NULL)
return -1;
if(p->next==NULL)//如果找到的前驱就是尾结点,就退出程序
{
printf("delete pos is invaild\n");
return -1;
}
p->next=q->next;
free(q);
q=NULL;//防止q成为野指针
return 0;
}
/*
清除掉整个链表
*/
int list_free(linklist H)
{
linklist p;
if(H==NULL)
{
printf("H is NULL\n");
return -1;
}
while(H!=NULL)
{
p=H;
free(p);
H=H->next;
}
}
/*
遍历打印链表数据
*/
int list_show(linklist H)
{
linklist p=H;
if(H==NULL)
{
printf("H is NULL\n");
return -1;
}
while(p->next!=NULL)
{
printf("%d",p->next->data);//从首元节点开始打印,头结点中没有数据不打印
p=p->next;
}
puts("");
return 0;
}
/*
链表反转
*/
int list_reverse(linklist H)
{
linklist p;
linklist q;
if(H==NULL)
{
printf("H is NULL\n");
return -1;
}
if(H->next==NULL||H->next->next==NULL)
{
printf("dont need to reverse");
return -1;
}
p=H->next->next; //先把链表断开 断成H->0 和1->2->3
H->next->next=NULL;
while(p!=NULL)
{
q=p;
q->next=H->next;//把1节点接到H后面 H->1->0
H->next=q;
p=p->next;
}
return 0;
}
/*
合并两个有序链表,并按照顺序排列
*/
int list_merge(linklist H1,linklist H2)
{
linklist p,q,r;
if(H1==NULL||H2==NULL)
{
printf("H1/H2 is NULL\n");
return -1;
}
p=H1->next;
q=H2->next;
r=H1;
H1->next=NULL;
H2->next=NULL;
while(p&&q)
{
if(p->data<=q->data)
{
r->next=p;
p=p->next;
r=r->next;
r->next=NULL;
}
else
{
r->next=q;
q=q->next;
r=r->next;
r->next=NULL;
}
}
if(p==NULL)
{
r->next=q;
}
else
{
r->next=p;
}
return 0;
}
linklist.h(头文件)
#include <stdio.h>
#include <stdlib.h>
typedef int data_t;
typedef struct node
{
data_t data;
struct node *next;
}listnode, *linklist;
linklist list_create();
int list_tail_insert(linklist H,data_t value);//head
linklist list_get(linklist H,int pos);
int list_insert(linklist H,data_t value,int pos);
int list_delete(linklist H,int pos);
int list_show(linklist H);
int list_free(linklist H);
int list_reverse(linklist H);
int list_merge(linklist H1,linklist H2);
test.c(测试代码)
int main()
{
//test_get();
//test_insert();
test_delete();
}
void test_get()
{
linklist H;
linklist p;
int value;
H=list_create();
printf("input:");
while(1)
{
scanf("%d",&value);
if(value==-1)
break;
list_tail_insert(H,value);
printf("input:");
}
list_show(H);
p=list_get(H,0);
if(p!=NULL)//防止p=NULL时,取值造成段错误
printf("value=%d\n",p->data);
}
void test_insert()
{
linklist H;
int value;
H=list_create();
printf("input:");
while(1)
{
scanf("%d",&value);
if(value==-1)
break;
list_tail_insert(H,value);
printf("input:");
}
list_show(H);
list_insert(H,100,3);
list_show(H);
}
void test_delete()
{
linklist H;
int value;
H=list_create();
printf("input:");
while(1)
{
scanf("%d",&value);
if(value==-1)
break;
list_tail_insert(H,value);
printf("input:");
}
list_show(H);
list_delete(H,2);
list_show(H);
}