数据结构—线性表的实现
昨天开始看《大话数据结构》中的线性表章节,根据物理结构大概分为两种:顺序存储结构和链式存储结构 其中顺序结构用数组来实现,在链式存储结构中又 分为 静态链表和动态链表 其中静态链表也是用数组所实现的,再具体还能分成 单链表,循环链表,双向链表,其中单链表在我之前的博客中已经提到过,就不再赘述了,下面 我大概介绍 线性表中的 顺序存储结构,静态链表,和双向循环链表。
1.顺序存储结构
定义:用一段地址连续的存储单元依次存放线性表的数据元素。
实现方式:使用以下的结构体来实现顺序存储结构线性表的功能:
#define MAX 20
typedef struct {
int date[MAX];
int length;
}SqList;
结构体中包含了两个成员:存放数据的数组,和数据长度。
插入数据元素思路:插入时,先找到插入位置,再从最后一位到这个位置上的数组元素全部向后移动一位,将数据写入这个位置,最后给数据长度加一。时间复杂度O(n)
删除数据元素思路:删除时,找到这个元素的位置,从这个位置开始之后到最后一位中间的元素全部向前移动一位,最后给数据长度减一。时间复杂度O(n)
以下是代码实现:
#include<stdio.h>
#define MAX 20
typedef struct {
int date[MAX];
int length;
}SqList;
SqList Creat(SqList list){
printf("请输入数据元素个数:");
scanf("%d",&list.length);
for(int i = 0; i < list.length; i++)
scanf("%d",&list.date[i]);
return list;
}
void print_list(SqList list){
for(int i = 0; i < list.length; i++){
printf("表中第%d个数据元素:",i+1);
printf("%d\n",list.date[i]);
}
}
SqList insert(SqList list){
if(list.length == 0){
printf("目前为空表!");
return list;
}
int site;
int elem;
printf("请输入要插入的位置:");
scanf("%d",&site);
if(site < 1 || site > list.length){
printf("位置输入有误!");
return list;
}
printf("要插入的数据:");
scanf("%d",&elem);
for(int i = list.length-1; i >= site-1; i--)
list.date[i+1] = list.date[i];
list.date[site-1] = elem;
list.length++;
printf("插入成功!");
return list;
}
SqList delete_elem(SqList list){
if(list.length == 0){
printf("目前为空表!");
return list;
}
int site;
printf("请输入要删除的位置:");
scanf("%d",&site);
if(site < 1 || site > list.length){
printf("位置输入有误!");
return list;
}
for(int i = site-1; i < list.length; i++)
list.date[i] = list.date[i+1];
list.length--;
return list;
}
int main(){
SqList list;
list = Creat(list);
print_list(list);
list = insert(list);
print_list(list);
list = delete_elem(list);
print_list(list);
return 0;
}
2.静态链表
定义:用数组描述的链表叫做静态链表。
实现方式:使用以下的结构体数组来实现静态链表的功能:
#define MAX 1000
typedef struct{
int date;
int cur;
}node,list[MAX];
每个结构体中包含两个成员:date代表数据,cur代表指向,cur拥有类似于单链表中节点指针域的作用,他存放下一个节点的下标
另外,在静态链表中,结构体数组的第一位和最后一个都不存放数据元素,第一位的成员cur代表 备用节点的位置(即还未存放数据的节点的下标)。最后一位的成员cur代表 静态链表的开始节点下标(拥有类似于头节点的作用)。
插入数据元素思路:插入时,新开辟一个节点并存入数据,找到要插入位置的前一个节点,将这个节点中的cur指向最新开辟的这个节点的下标,然后将要插入位置节点的下标赋值给新开辟节点的cur,这样不需要移动大量元素就可以实现新节点的插入。
删除数据元素思路:删除时,先找到要删除节点的位置和要删除节点的前一个节点的位置,将前一个节点的cur指向要删除节点的cur,再释放掉要删除的节点(将其纳入备用节点中,并改变其cur为下一个备用节点下标)。
以下是代码实现:
#include<stdio.h>
#define MAX 1000
typedef struct{
int date;
int cur;
}node,list[MAX]; //静态链表
void InitList(list space){
for(int i = 0; i < MAX-1; i++)
space[i].cur = i+1;
space[MAX-1].cur = 0;
}
void creat(list space){
int index;
int i;
printf("请输入数据元素个数:");
scanf("%d",&index);
for(i = 1; i <= index; i++)
scanf("%d",&space[i].date);
space[i-1].cur = 0;
space[0].cur = index+1;
space[MAX-1].cur = 1;
}
void print_list(list space){
int index = 0;
int end = MAX-1;
while(space[end].cur != 0){
end = space[end].cur;
printf("第%d个数据元素:",++index);
printf("%d\n",space[end].date);
}
}
int malloc_node(list space){
int i = space[0].cur;
if(space[0].cur)
space[0].cur = space[i].cur;
return i;
}
void insert(list space){
int site;
int elem;
int pre = MAX-1;
int obj = malloc_node(space);
printf("请输入要插入的位置:");
scanf("%d",&site);
printf("请输入要插入的数据:");
scanf("%d",&elem);
if(obj){
space[obj].date = elem;
for(int i = 1; i <= site-1; i++)
pre = space[pre].cur;
space[obj].cur = space[pre].cur;
space[pre].cur = obj;
}
printf("插入成功!\n");
}
void free_node(list space,int k){
space[k].cur = space[0].cur;
space[0].cur = k;
}
void delete_node(list space){
int site;
int pre = MAX-1;
printf("请输入要删除的位置:");
scanf("%d",&site);
for(int i = 1; i <= site-1; i++)
pre = space[pre].cur;
int now = space[pre].cur;
space[pre].cur = space[now].cur;
free_node(space,now);
printf("删除成功!\n");
}
int main(){
list space;
InitList(space);
creat(space);
print_list(space);
insert(space);
print_list(space);
delete_node(space);
print_list(space);
return 0;
}
3.双向循环链表
定义:每个节点,既有前驱,又有后继,且链表末尾指向头节点的链表。
实现方式:在单链表的前提下为每个节点新增一个指向前一个节点的指针:
struct NODE{
int date;
struct NODE *prior;
struct NODE *next;
};
typedef struct NODE *node;
int count = 0;
在使用双向循环链表后,许多操作会方便很多,因为现在既可以向后遍历,也可以向前遍历,头节点和尾节点相连更是提高了算法的时间性能。说白了就是用空间来换时间
插入,删除数据思路与单链表相同
以下是代码实现:
#include<stdio.h>
#include<stdlib.h>
struct NODE{
int date;
struct NODE *prior;
struct NODE *next;
};
typedef struct NODE *node;
int count = 0;
node Creat(node pHead){
int index;
node pNew = NULL,pEnd = NULL;
pHead = (node)malloc(sizeof(struct NODE));
pHead->next = pHead;
pHead->prior = pHead;
pEnd = pHead;
printf("请输入数据元素个数:");
scanf("%d",&index);
for(int i = 0; i < index; i++){
count++;
pNew = (node)malloc(sizeof(struct NODE));
scanf("%d",&pNew->date);
pNew->next = pHead;
pHead->prior = pNew;
pEnd->next = pNew;
pNew->prior = pEnd;
pEnd = pNew;
}
return pHead;
}
void print_list(node pHead){
int choice;
int index = 0;
node pRear,pTemp;
pRear = pHead->prior;
pTemp = pHead->next;
printf("请选择1.正序输出 或 2.倒序输出\n");
scanf("%d",&choice);
if(choice == 1){
while(pTemp != pHead){
printf("第%d个数据元素:",++index);
printf("%d\n",pTemp->date);
pTemp = pTemp->next;
}
}
else if(choice == 2){
while(pRear != pHead){
printf("第%d个数据元素:",count-index++);
printf("%d\n",pRear->date);
pRear = pRear->prior;
}
}
}
node insert(node pHead){
int site;
node pNew,pTemp,pPre;
pTemp = pHead->next;
printf("请输入要插入的位置:");
scanf("%d",&site);
for(int i = 1; i < site; i++)
pTemp = pTemp->next;
pNew = (node)malloc(sizeof(struct NODE));
printf("请输入要插入的数据:");
scanf("%d",&pNew->date);
pPre = pTemp->prior;
pNew->prior = pPre;
pNew->next = pTemp;
pTemp->prior = pNew;
pPre->next = pNew;
count++;
printf("插入成功!\n");
return pHead;
}
node delete_node(node pHead){
int site;
node pTemp,pPre;
pTemp = pHead->next;
printf("请输入要删除的位置:");
scanf("%d",&site);
for(int i =1; i < site;i++)
pTemp = pTemp->next;
pPre = pTemp->prior;
pPre->next = pTemp->next;
pTemp->next->prior = pPre;
free(pTemp);
printf("删除成功!\n");
return pHead;
}
int main(){
node pHead = NULL;
pHead = Creat(pHead);
print_list(pHead);
pHead = insert(pHead);
print_list(pHead);
delete_node(pHead);
print_list(pHead);
return 0;
}