顺序存储结构和链式存储结构
线性表存储数据可细分为以下 2 种:
1.将数据依次存储在连续的整块物理空间中,这种存储结构称为顺序存储结构(简称顺序表);
2.数据分散的存储在物理空间中,通过一根线保存着它们之间的逻辑关系,这种存储结构称为链式存储结构(简称链表);
也就是说,线性表存储结构可细分为顺序存储结构和链式存储结构。
一:顺序表
顺序表的存储结构定义
#define Size 5
typedef struct Table{
int *head;//声明了一个名为head的长度不确定的数组,也叫“动态数组”
int length;//记录当前顺序表的长度
int size;//记录顺序表分配的存储容量
}table;
顺序表中基本操作的实现
#include <stdio.h>
#include <stdlib.h>
#define Size 5
typedef struct Table
{
int *head; //存储空间的基地址
int length; //当前长度
int size; //顺序表的大小
}table;
//顺序表的初始化
table InitTable()
{
table t;
t.head=(int*)malloc(Size*sizeof(int));
if(t.head == NULL)
{
printf("初始化失败\n");
exit(0);
}
t.length=0;
t.size=Size;
return t;
}
//顺序表的插入
table addElem(table t,int elem,int index)
{
if(index<1 || index>t.length+1)
{
printf("插入的位置有误\n");
return t;
}
if (t.length>=t.size)
{
t.head=(int *)realloc(t.head, (t.size+1)*sizeof(int));
if (t.head == NULL)
{
printf("存储分配失败\n");
}
t.size+=1;
}
for(int i=t.length-1;i>=index-1;i--)
{
t.head[i+1]=t.head[i];
}
t.head[index-1]=elem;
t.length++;
return t;
}
//顺序表的遍历
void displayTable(table t)
{
for(int i=0;i<t.length;i++)
{
printf("%d ",t.head[i]);
}
printf("\n");
}
//顺序表的查找
int SelectElem(table t,int index)
{
for(int i=0;i<t.length;i++)
{
if(index==i+1)
{
return t.head[i];
}
}
return -1;
}
//顺序表的删除
table deleteElem(table t,int index)
{
if (index>t.length || index<1) {
printf("被删除元素的位置有误\n");
return t;
}
for(int i=index;i<=t.length-1;i++)
{
t.head[i-1]=t.head[i];
}
t.length--;
return t;
}
//顺序表的修改
table updateElem(table t,int elem,int index)
{
for(int i=0;i<=t.length-1;i++)
{
if(index == i+1)
{
t.head[i]=elem;
}
}
return t;
}
int main()
{
table t;
t=InitTable();
for(int i=1;i<=Size;i++)
{
t.head[i-1]=i;
t.length++;
}
displayTable(t);
int a = SelectElem(t,2);
printf("%d\n",a);
t = addElem(t,100,2);
displayTable(t);
t = deleteElem(t,2);
displayTable(t);
t = updateElem(t,666,5);
displayTable(t);
return 0;
}
二:链表
1.单链表
头节点,头指针和首元节点
一个完整的链表需要由以下几部分构成:
头指针:一个普通的指针,它的特点是永远指向链表第一个节点的位置。很明显,头指针用于指明链表的位置,便于后期找到链表并使用表中的数据;
节点:链表中的节点又细分为头节点、首元节点和其他节点:
头节点:其实就是一个不存任何数据的空节点,通常作为链表的第一个节点。对于链表来说,头节点不是必须的,它的作用只是为了方便解决某些实际问题;
首元节点:由于头节点(也就是空节点)的缘故,链表中称第一个存有数据的节点为首元节点。首元节点只是对链表中第一个存有数据节点的一个称谓,没有实际意义;
其他节点:链表中其他的节点;
单链表的存储结构定义
typedef struct LNode
{
int data;
struct LNode *next;
} LNode,*LinkList;
单链表基本操作的实现
#include <stdio.h>
#include <stdlib.h>
typedef struct LNode
{
int data;
struct LNode *next;
} LNode,*LinkList;
//采用头插法创建链表
LinkList createList1()
{
LinkList head;
int length,x;
head=(LinkList)malloc(sizeof(LinkList));
head->next=NULL;
printf("请输入节点的个数\n");
scanf("%d",&length);
for(int i=0; i<length; i++)
{
LinkList p;
p=(LinkList)malloc(sizeof(LinkList));
p->next=NULL;
printf("请输入要存储的数:\n");
scanf("%d",&x);
p->data=x;
p->next=head->next;
head->next=p;
}
return head;
}
//采用尾插法创建链表
LinkList createList2()
{
LinkList head;
int length,x;
head=(LinkList)malloc(sizeof(LinkList));
head->next=NULL;
LinkList r=head;
printf("请输入结点个数\n");
scanf("%d",&length);
for(int i=0; i<length; i++)
{
LinkList p;
p=(LinkList)malloc(sizeof(sizeof(LinkList)));
p->next=NULL;
printf("请输入要存储的数:\n");
scanf("%d",&x);
p->data=x;
r->next=p;
r=p;
}
return head;
}
//单链表的遍历
void dispList(LinkList head)
{
LinkList p=head;
printf("链表中的数据如下:\n");
while((p->next)!=NULL)
{
printf("%d\n",p->next->data);
p=p->next;
}
}
//单链表的插入
LinkList addElem(LinkList head,int elem,int add)
{
LinkList p=head;
for(int i=1; i<add; i++)
{
p=p->next;
if (p == NULL)
{
printf("插入位置无效\n");
return p;
}
}
LinkList c;
c=(LinkList)malloc(sizeof(LinkList));
c->data=elem;
c->next=p->next;
p->next=c;
return head;
}
//删除指定位置的结点
LinkList deleteElem(LinkList head,int del)
{
LinkList p=head;
for(int i=1; i<del; i++)
{
p=p->next;
if(p->next==NULL)
{
printf("结点不存在!!\n");
return p;
}
}
LinkList d=p->next;
p->next=p->next->next;
free(d);
return head;
}
//删除所有结点数据域值为x的结点,结点不唯一
LinkList delnode(LinkList head, int x)
{
LinkList p=head;
while(p->next!=NULL){
LinkList a = p->next;
if(a->data==x){
p->next=a->next;
free(a);
}else{
p=p->next;
}
}
return head;
}
//采用头插法逆置单链表
LinkList Inverse(LinkList head)
{
LinkList p,q;
p = head->next;
head->next=NULL;
while(p!=NULL){
q = p->next;
p->next = head->next;
head->next = p;
p = q;
}
return head;
}
int main()
{
LinkList head=createList2();
dispList(head);
head = Inverse(head);
printf("逆置后元素排序:\n");
dispList(head);
printf("请输入要删除的节点数据\n");
int data;
scanf("%d",&data);
head = delnode(head,data);
dispList(head);
printf("请输入要插入的位置\n");
int elem,add;
scanf("%d",&add);
printf("请输入要插入的数值\n");
scanf("%d",&elem);
head=addElem(head,elem,add);
dispList(head);
printf("请输入要删除的位置\n");
int del;
scanf("%d",&del);
head=deleteElem(head,del);
dispList(head);
return 0;
}
2.循环链表
若将两个线性表合并成一个表时,仅需要将第一个表的尾指针指向第二个表的第一个结点,第二个表的尾指针指向第一个表的头结点,然后释放第二个表的头结点。
p = B->next->next;
B->next = A->next;
A->next = p;