一、实现双向循环链表
main.c
#include "loop.h"
int main(int argc, const char *argv[])
{
node_p H=create_link();
insert_head(H,7);
show_node(H);
insert_tail(H,9);
show_node(H);
insert_tail(H,47);
show_node(H);
insert_tail(H,23);
show_node(H);
insert_tail(H,19);
show_node(H);
insert_tail(H,11);
show_node(H);
dele_head(H);
show_node(H);
dele_tail(H);
show_node(H);
int pos=2;
printf("%d\n",seek_pos(H,pos));
return 0;
}
loop.c
#include "loop.h"
//1、创建头结点
node_p create_link()
{
node_p H=(node_p)malloc(sizeof(node));
if(H==NULL)
{
printf("申请空间失败");
return NULL ;
}
H->len=0;
H->next=NULL;
H->pri=H;
return H ;
}
//2、创建链表结点
node_p create_node(int value)
{
node_p new=(node_p)malloc(sizeof(node));
if(new==NULL)
{
printf("申请空间失败");
return NULL ;
}
new->data=value;
new->pri=NULL;
new->next=NULL;
return new ;
}
//3、判空
int empty_node(node_p H)
{
if(H==NULL) {return -1;}
return H->next==NULL? 1:0;
}
//4、头插
void insert_head(node_p H,int value)
{
if(H==NULL) { return ;}
node_p new=create_node(value);
new->pri=H;
//新结点的前驱指向头结点
if(H->next!=NULL)
{
H->next->pri=new;
//头结点后驱结点的前驱指向新结点
new->next=H->next;
//新结点的后驱指向头结点的后驱
}
else
{
H->pri=new;
new->next=H; //新结点的后驱指向头结点的后驱
}
H->next=new;
H->len++;
return ;
}
//6、按位置插入
void insert_pos(node_p H,int pos,int value)
{
if(H==NULL) { return ;}
//判断插入位置是否合理
if(pos<1 || pos>H->len)
{
printf("插入元素位置不合理\n");
return ;
}
int i;
node_p p;
//循环找出需要插入元素的位置
for(i=0,p=H;i<pos-1;i++,p=p->next)
{
//如果该位置为尾结点,则调用尾插函数
if(p->next==NULL)
{
insert_tail(H,value);
return ;
}
}
node_p new=create_node(value);
new->pri=p; //新结点的前驱指向P结点
if(p->next!=NULL)
{
new->next=p->next; //新结点后驱指向p结点后驱
p->next->pri=new; //p结点的后驱的前驱指向新结点
}
else
{
new->next=H;
H->pri=new;
}
p->next=new; //p结点的后驱指向新结点
H->len++;
return ;
}
//7、头删
void dele_head(node_p H)
{
if(H==NULL) { return ;}
if(empty_node(H))
{
printf("链表元素为空,无须删除\n");
return ;
}
node_p p=H->next;
if(p->next==NULL)
{
free(p);
H->next=NULL;
H->pri=NULL;
H->len--;
}
p->next->pri=H; //p结点的后驱的前驱指向头结点
H->next=p->next; //头结点的后驱指向p结点的后驱
free(p);
H->len--;
return ;
}
//8、尾删
void dele_tail(node_p H)
{
if(H==NULL) { return ;}
if(empty_node(H))
{
printf("链表元素为空,无须删除\n");
return ;
}
node_p p=H;
while(p->next->next!=NULL)
{
p=p->next;
}
H->pri=p->next->pri; //头结点的前驱指向p结点
p->next=H; //p结点的后驱指向头结点
free(p->next); //释放p结点的后驱结点
H->len--;
}
//9、按位置删除
void dele_pos(node_p H,int pos)
{
if(H==NULL) { return ;}
if(empty_node(H))
{
printf("链表元素为空,无须删除\n");
return ;
}
if(pos<1 || pos>H->len)
{
printf("删除元素位置不合理\n");
return ;
}
int i;
node_p p;
//循环找出需要删除元素的位置
for(i=0,p=H;i<pos-1;i++,p=p->next);
if(p->next==NULL)
{
p->pri->next=H;
H->pri=p->pri;
free(p);
H->len--;
}
p->next->pri=p->pri; //p结点后驱的前驱指向p结点的前驱
p->pri->next=p->next; //p结点前驱的后驱指向p结点的后驱
free(p);
H->len--;
}
//10、按位置查找
int seek_pos(node_p H,int pos)
{
if(H==NULL) { return -1;}
if(empty_node(H))
{
printf("链表元素为空,无法找到目标值\n");
return -2;
}
if(pos<1 || pos>H->len)
{
printf("删除元素位置不合理\n");
return -3;
}
int i;
node_p p;
//循环找出目标位置的元素
for(i=0,p=H;i<pos-1;i++,p=p->next);
int num=p->data; //获取目标位置的元素
return num;
}
//输出链表
void show_node(node_p H)
{
if(H==NULL) { return ;}
if(empty_node(H))
{
printf("链表元素为空,无须打印\n");
return ;
}
node_p p=H->next;
do
{
printf("%d-> ",p->data);
p=p->next;
}while(p->next!=H);
return;
}
loop.h
#ifndef __LOOP_H__
#define __LOOP_H__
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
typedef struct node
{
union
{
int data;
int len;
};
struct node *pri;
struct node *next;
}node,* node_p;
node_p create_link();
node_p create_node(int value);
int empty_node(node_p H);
void insert_head(node_p H,int value);
void insert_tail(node_p H,int value);
void insert_pos(node_p H,int pos,int value);
void dele_head(node_p H);
void dele_tail(node_p H);
void dele_pos(node_p H,int pos);
int seek_pos(node_p H,int pos);
void show_node(node_p H);
#endif
二、链表和顺序表的优缺点:
顺序表可通过下标访问,访问速度快,静态分配内存利用高,插入和删除需要移动后续数据效率低。
链表通过指针访问,访问速度慢,动态分配内存利用不高,插入和删除可通过指针完成效率高。
三、牛客刷题

1557

被折叠的 条评论
为什么被折叠?



