文中大部分程序来自于同学、老师;部分为作者原创或改编。
0 线性表的定义
线性表是基本数据结构之一,其定义为n个数据元素的有限序列。根据线性表的定义,我们将线性表记为:
则有ai-1领先于ai,ai领先于ai+1,因此我们将ai-1称为ai的直接前驱元素,将aI+1称为ai的直接后继元素。
线性表中数据元素之间是一对一的关系,即除了第一个和最后一个数据元素之外,其它数据元素都是首尾相接的(循环链表逻辑层次上也是一种线性表,但是把最后一个数据元素的尾指针指向了首位结点)。
1 顺序存储实现方式
特点:存储单元的地址连续。
优点:可直接访问任意地址元素。
缺点:增加或删除元素时需依次移动大量的元素。
源程序如下:
#include <stdio.h>
#include <malloc.h>
#define DATATYPE1 int
#define MAXSIZE 100
typedef struct
{
DATATYPE1 datas[MAXSIZE];
int last;
}SEQUENLIST;
/*初始化表的长度为0*/
void initiate (SEQUENLIST *a)
{
a->last=0;
}
/*在表尾添加元素*/
void insertrear(SEQUENLIST *a,DATATYPE1 x)
{
a->datas[a->last]=x;
a->last++;
}
/*将元素x添加到表的第i位置*/
int insert(SEQUENLIST * a,DATATYPE1 x,int i)
{
int k;
if(i<1||i>a->last+1||a->last>=MAXSIZE)
return 0;
else
{
for(k=a->last;k>=i;k--)
a->datas[k]=a->datas[k-1];
//依次后移元素
a->datas[i-1]=x;
a->last=a->last+1;
return 1;
}
}
/*将x添加到有序表中且保证表依然有序*/
void insert1(SEQUENLIST *a,DATATYPE1 x)
{
int i;
for(i=0;i<a->last;i++)
{
if(a->datas[i]>=x)
break;
//找到首个大于x元素即可退出
}
insert(a,x,i+1);
}
/*删除表的第i个元素*/
int delpos(SEQUENLIST *a,int i)
{
int j;
if(i<1||i>a->last||a->last==0)
return 0;
for(j=i;j<a->last;j++)
a->datas[j-1]=a->datas[j];
//依次前移数据
a->last--;
return 1;
}
/*删除表中的重复元素*/
int delsame(SEQUENLIST *a)
{
int i,j,k,flag=0;
if(a->last==0)
return 0;
for(i=0;i<a->last;i++)
for(j=i+1;j<a->last;j++)
if(a->datas[i]==a->datas[j])
{
for(k=j+1;k<a->last;k++)
a->datas[k+1]=a->datas[k];
//依次前移删除j位置数据
a->last--;
flag=1;
j--;
//j自减,以重新检查j位置元素
}
return flag;
}
/*遍历输出*/
void traverse(SEQUENLIST*a)
{
int i;
for(i=0;i<a->last;i++)
printf("%d",a->datas[i]);
printf("\n");
}
int main()
{
int i,n;
DATATYPE1 x;
SEQUENLIST b;
initiate(&b);
//初始化表b
printf("Please input 10 number: \n");
for(i=0;i<10;i++)
{
scanf("%d",&x);
insertrear(&b,x);
//向表b的尾部添加元素x
}
printf("the original list:\n");
traverse(&b);
//输出b中的元素
printf("Please input the position and nymber for insert(n,x):\n");
scanf("%d,%d",&n,&x);
insert(&b,x,n);
//将元素x添加到表b的第n位置
printf("the new list after insert:\n");
traverse(&b);
initiate(&b);
printf("Please input 10 number:\n");
for(i=0;i<10;i++)
{
scanf("%d",&x);
insert1(&b,x);
//向有序表b中添加元素x且使表b依然有序
}
printf("the ordered listt created by inserting x to a suitable position:\n");
traverse(&b);
initiate(&b);
printf("Please input 10 number(with same elements):\n");
for(i=0;i<10;i++)
{
scanf("%d",&x);
insert(&b,x,1);
//将元素x添加到b的首位置
}
printf("the list created by inserting from front:\n");
traverse(&b);
printf("input the position where the element is to be deleted:\n");
scanf("%d",&n);
delpos(&b,n);
//删除b的第n位置元素
printf("the list after deleting NO.%d element:\n",n);
traverse(&b);
delsame(&b);
//删除b中的重复元素
printf("the list after deleting extra same element:\n");
traverse(&b);
return 0;
}
2 链式存储实现方式
特点:存储单元的地址连续。
优点:增加或删除元素仅需操作直接前驱和直接后继元素。
缺点:访问元素时需遍历寻找。
源程序如下:
#include<stdio.h>
#include<malloc.h>
#define ELEMTYPE char
typedef struct node
{
ELEMTYPE data;
struct node *next;
}LINKLIST;
/*创建单链表*/
LINKLIST *create()
{
LINKLIST *head,*last,*t;
char ch;
head=(LINKLIST *)malloc(sizeof(LINKLIST));
head->next=NULL;
last=head;
printf("input some charcters ended with '#':\n");
while((ch=getchar())!='#')
{
t=(LINKLIST*)malloc(sizeof(LINKLIST));
t->data=ch;
last->next=t;
last=t;
//在尾部添加新元素
}
last->next=NULL;
return head;
}
/*将x添加到链表尾部*/
LINKLIST *insertrear(LINKLIST *head,ELEMTYPE x)
{
LINKLIST *p,*t;
t=(LINKLIST *)malloc(sizeof(LINKLIST));
t->data=x;
t->next=NULL;
p=head;
while(p->next!=NULL)
p=p->next;
p->next=t;
return head;
}
/*将x添加为链表首元素*/
LINKLIST *insertfront(LINKLIST *head,ELEMTYPE x)
{
LINKLIST *t;
t=(LINKLIST *)malloc(sizeof(LINKLIST));
t->data=x;
t->next=head->next;
head->next=t;
return head;
}
/*将x添加到链表的第pos位置*/
LINKLIST *insertpos(LINKLIST *head,ELEMTYPE x,int pos)
{
LINKLIST *p, *t;
int n=0;
p=head->next;
while(p!=NULL)
{
n++;
if(n==pos)break;
p=p->next;
//遍历寻找
}
if(p!=NULL)
{
t=(LINKLIST*)malloc(sizeof(LINKLIST));
t->data=x;
t->next=p->next;
p->next=t;
}
return head;
}
/*在链表中删除为元素x*/
LINKLIST *deleteval(LINKLIST *head,ELEMTYPE x)
{
LINKLIST *p, *q;
q=head;
p=head->next;
while(p!=NULL)
{
if(p->data==x)break;
q=p;
p=p->next;
}
if(p!=NULL)
{
q->next=p->next;
free(p);
}
return head;
}
/*遍历输出*/
void output(LINKLIST *head)
{
LINKLIST *p;
p=head->next;
while(p!=NULL)
{
printf("%c",p->data);
p=p->next;
}
printf("\n");
}
int main()
{
LINKLIST *head;
char ch;
int i;
head=create();
//创建链表
printf("the link list:\n");
output(head);
//显示链表
printf("input a character to be inserted:\n");
fflush(stdin);
//清空缓冲区,即清除换行键的影响
ch=getchar();
head=insertfront(head,ch);
//添加表的首元素为ch
printf("the link list after insertig from front:\n");
output(head);
printf("input a character to be inserted:\n");
fflush(stdin);
ch=getchar();
head=insertrear(head,ch);
//添加表的尾元素为ch
printf("the link list after inserting from rear:\n");
output(head);
printf("input a character and position for insertion(x,i):\n");
fflush(stdin);
scanf("%c,%d",&ch,&i);
head=insertpos(head,ch,i);
//添加表的第i元素为ch
printf("the link list after inserting:\n");
output(head);
fflush(stdin);
printf("input a character to be deleted:\n");
fflush(stdin);
scanf("%c",&ch);
head=deleteval(head,ch);
//删除表中为ch的元素
printf("the link list after deleting:\n");
output(head);
return 0;
}
3 其他函数
(1)链表合并
要求:合并两个有序(从小到大)链表,合并后依然有序。
/*链表合并*/
LINKLIST *merge(LINKLIST *hd1, LINKLIST *hd2)
{
if(hd1 == NULL)return hd2;
if(hd2 == NULL)return hd1;
//到某一表结尾直接返回另一表地址即可
LINKLIST *h;
if(hd1->data < hd2->data){
h = hd1;
h->next = merge(hd1->next,hd2);
}
else{
h = hd2;
h->next = merge(hd1,hd2->next);
}
return h;
}
(2)清除重复数据
这是另一种清除重复数据的方法,同样适用于顺序存储方式。这种方法将一步一步的前移更改为了直接的移动,但是相比于原函数多占用了大小为MAXSIZE * sizeof(int)的空间。
int delsameT(SEQUENLIST *a)
{
int f[MAXSIZE] = {0};
if(a->last == 0)
return 0;
for(int i = 0; i<a->last; i++){
if(f[i] == 1)continue;
//已标记数据可以认为是无用数据,无需进行后续操作
for(int j = i+1; j<a->last; j++){
if(a->datas[i] ==a->datas[j])f[j] = 1;
}
}
int k = 0;
int num = 0;
while(k < a->last){
if(f[k] == 0)a->datas[num++] = a->datas[k];
k++;
}//消除无意义数据项
a->last = num;//更新last
return 1;
}
//待补充更新