25072班8.25日 数据结构作业
思维导图
完成双向循环链表的重要功能代码
双向循环链表头插
//头插
void head_insert(dlink_p head,int element)
{//判存if(head==NULL){printf("头插:链表不存在!\n");return ;}dlink_p p=create_node(element);p->next=head->next;p->prev=head;head->next=p;p->next->prev=p;head->len++;
}
双向循环链表尾插
//尾插
void last_insert(dlink_p head,int element)
{//判存if(head==NULL){printf("头插:链表不存在!\n");return ;}//尾节点dlink_p p=head;//新节点dlink_p q=create_node(element);if(head->next!=NULL){while(p->next!=head){p=p->next;}}q->next=head;q->prev=p;p->next=q;head->prev=q;head->len++;
}
双向循环链表头删
//头删
void head_del(dlink_p head)
{//判存if(head==NULL){printf("头删:链表不存在!\n");return ;}//判空if(empty(head)==-1){printf("头删:链表为空!\n");return ;}dlink_p del=head->next;if(del->next==head){head->next=head;}else{del->next->prev=head;head->next=del->next;head->len--;}free(del);del=NULL;
}
双向循环链表尾删
//尾删
void last_del(dlink_p head)
{//判存if(head==NULL){printf("尾删:链表不存在!\n");return ;}//判空if(empty(head)==-1){printf("尾删:链表为空!\n");return ;}dlink_p p=head;while(p->next->next!=head){p=p->next;}dlink_p del=p->next;p->next=head;free(del);del=NULL;head->len--;
}
双向循环链表按位插
//位插
void pos_insert(dlink_p head,int pos,int element)
{//判存if(head==NULL){printf("按位插:链表不存在!\n");return ;}//判位if(pos_right(head,pos)<pos-1||pos<0){printf("按位插:输入位置不合理!\n");return ;}//创建新节点dlink_p q=create_node(element);dlink_p p=head;//找到pos位int i=0;while(i!=pos-1){i++;p=p->next;}q->next=p->next;q->prev=p;p->next=q;p->next->prev=q;head->len++;
}
双向循环链表按位删
//按位删
void pos_del(dlink_p head,int pos)
{//判存if(head==NULL){printf("按位删:链表不存在!\n");return ;}//判位if(pos_right(head,pos)<pos-1||pos<0){printf("按位删:输入位置不合理!\n");return ;}dlink_p p=head;//找到pos位int i=0;while(i!=pos){i++;p=p->next;}p->prev->next=p->next;p->next->prev=p->prev;free(p);p=NULL;head->len--;
}
源码(功能代码)
#include "head.h"
//创建头结点
dlink_p create_head()
{//申请空间dlink_p head=(dlink_p)malloc(sizeof(dlink));if(head==NULL){printf("头结点创建失败!\n");return NULL;}//初始化头结点head->next=head;head->prev=head;head->len=0;return head;
}
//创建节点
dlink_p create_node(int element)
{//申请空间dlink_p p=(dlink_p)malloc(sizeof(dlink));if(p==NULL){printf("创建节点:创建失败!\n");return NULL;}//初始化节点p->data=element;p->next=p;p->prev=p;return p;
}
//判空
int empty(dlink_p head)
{if(head->next==head){printf("空!\n");return -1;}return 0;
}
//头插
void head_insert(dlink_p head,int element)
{//判存if(head==NULL){printf("头插:链表不存在!\n");return ;}dlink_p p=create_node(element);p->next=head->next;p->prev=head;head->next=p;if(p->next!=head){p->next->prev=p;}else{head->prev=p;}head->len++;}
//尾插
void last_insert(dlink_p head,int element)
{//判存if(head==NULL){printf("头插:链表不存在!\n");return ;}//尾节点dlink_p p=head;//新节点dlink_p q=create_node(element);if(head->next!=NULL){while(p->next!=head){p=p->next;}}q->next=head;q->prev=p;p->next=q;head->prev=q;head->len++;}
//输出
void output(dlink_p head)
{//判存if(head==NULL){printf("输出:链表不存在!\n");return ;}//判空if(empty(head)==-1){printf("输出:链表为空!\n");return;}dlink_p p=head->next;while(p!=head){printf("%-4d",p->data);p=p->next;}putchar(10);}
//判位
int pos_right(dlink_p head,int pos)
{dlink_p p=head->next;int i=1;while(p->next!=head){p=p->next;i++;}return i;
}
//位插
void pos_insert(dlink_p head,int pos,int element)
{//判存if(head==NULL){printf("按位插:链表不存在!\n");return ;}//判位if(pos_right(head,pos)<pos-1||pos<0){printf("按位插:输入位置不合理!\n");return ;}//创建新节点dlink_p q=create_node(element);dlink_p p=head;//找到pos位int i=0;while(i!=pos-1){i++;p=p->next;}q->next=p->next;q->prev=p;p->next=q;if(p->next!=head){p->next->prev=q;}else{head->prev=q;}head->len++;
}//头删
void head_del(dlink_p head)
{//判存if(head==NULL){printf("头删:链表不存在!\n");return ;}//判空if(empty(head)==-1){printf("头删:链表为空!\n");return ;}dlink_p del=head->next;if(del->next==head){head->next=head;}else{del->next->prev=head;head->next=del->next;head->len--;}free(del);del=NULL;
}
//尾删
void last_del(dlink_p head)
{//判存if(head==NULL){printf("尾删:链表不存在!\n");return ;}//判空if(empty(head)==-1){printf("尾删:链表为空!\n");return ;}dlink_p p=head;while(p->next->next!=head){p=p->next;}dlink_p del=p->next;p->next=head;free(del);del=NULL;head->len--;}//按位删
void pos_del(dlink_p head,int pos)
{//判存if(head==NULL){printf("按位删:链表不存在!\n");return ;}//判位if(pos_right(head,pos)<pos-1||pos<0){printf("按位删:输入位置不合理!\n");return ;}dlink_p p=head;//找到pos位int i=0;while(i!=pos){i++;p=p->next;}p->prev->next=p->next;p->next->prev=p->prev;free(p);p=NULL;head->len--; }
整理顺序栈的代码,输出栈,销毁栈
输出栈
销毁栈
代码集
#include "head.h"
//创建顺序栈
stack_p create_stack()
{stack_p stk=(stack_p)malloc(sizeof(stack));if(stk==NULL){printf("创建顺序栈失败!\n");return NULL;}stk->top=-1;bzero(stk,sizeof(stk->data));return stk;}
//压数据入栈
void push_stack(stack_p stk,int element)
{if(stk==NULL){printf("入参为空,请检查\n");return;}//先加再压//先加栈顶位置,再将元素压入栈stk->data[++(stk->top)] = element;
}
//判空
int empty(stack_p stk)
{if(stk==NULL){printf("入参为空!\n");return -1;}return stk->top==-1;
}
//判满
int full(stack_p stk)
{ if(stk==NULL){printf("入参为空!\n");return -1;}return stk->top==MAX-1;
}
//出栈(弹栈)
int pop_stack(stack_p stk)
{if(stk==NULL){printf("入参为空!\n");return -1;}return stk->data[stk->top--];
}//输出
int main()
{//创建顺序栈stack_p stk=create_stack();int element;for(int i=0;i<MAX;i++){printf("请输入入栈元素:");scanf("%d",&element);push_stack(stk,element);}//循环输出for(int i=0;i<MAX;i++){printf("输出栈:%d\n",pop_stack(stk));}//销毁栈free(stk);stk=NULL;empty(stk);return 0;
}
总结顺序表和链表的区别和优缺点。
区别:
存储结构
顺序表:在内存中占用一段连续的存储空间,逻辑上相邻的元素在物理地址上也相邻。比如在 C 语言中,定义一个整型数组 int arr[5],它在内存中是连续存储这 5 个整数的 。
链表:是一种链式存储结构,每个节点除了存储数据元素外,还包含一个或多个指针,用于指向其他节点,节点在内存中的存储位置不一定连续。以单链表为例,每个节点包含数据域和指针域,指针指向下一个节点 。
数据元素的访问方式
顺序表:可以通过下标直接访问元素,时间复杂度为 O(1) 。例如,对于数组 arr,访问 arr[i] 可以直接定位到相应位置。
链表:只能从链表的头节点开始,通过指针依次向后查找元素,时间复杂度为 O(n),其中 n 是链表的长度。比如要找单链表中第 k 个节点,需要从表头开始遍历 k 次 。
插入和删除操作
顺序表:在插入或删除元素时,可能需要移动大量元素。例如在数组中间位置插入一个元素,需要将插入位置之后的所有元素向后移动一位,时间复杂度为 O(n) 。
链表:插入和删除操作相对简单,只需要修改指针指向即可。例如在单链表中插入一个节点,只需修改插入位置前一个节点的指针,时间复杂度为 O(1) ,但在找到插入位置前,可能需要遍历链表,整体时间复杂度在链表中间或尾部插入删除为 O(n),在头部插入删除为 O(1) 。
优点
顺序表
随机访问效率高:可以快速访问任意位置的元素,适合频繁进行查找操作的场景,比如在数组中查找学生成绩 。
存储密度高:不需要额外存储指针,空间利用率较高。
实现简单:在一些简单的场景下,顺序表的代码实现相对容易,理解和维护成本低 。
链表
插入和删除灵活:在插入和删除操作上不需要移动大量元素,效率更高,尤其适合数据频繁变动的场景,如实现一个任务队列,不断添加和删除任务 。
内存分配灵活:链表的节点在需要时才分配内存,不需要预先分配连续的大块内存,适合内存资源有限或数据量不确定的情况 。
缺点
顺序表
插入和删除效率低:在顺序表中间位置插入或删除元素时,需要移动大量元素,操作耗时较长。
空间扩展困难:如果需要增加顺序表的容量,可能需要重新分配更大的连续内存空间,并将原数据复制过去,操作复杂且耗时 。
链表
访问效率低:不能像顺序表那样随机访问元素,查找特定元素需要从头开始遍历,时间复杂度较高。
存储开销大:每个节点除了存储数据外,还需要存储指针,会占用一定的额外空间 。
实现相对复杂:链表的操作涉及到指针的管理,如指针的赋值、释放等,代码实现相对复杂,容易出现指针错误,如空指针引用、内存泄漏等问题 。