/*************************************************************************
> File Name: link_list.c
> Author: Andy001847
> Mail: yunzhonglai@hotmail.com
> Created Time: 2014年10月25日 星期六 11时51分34秒
************************************************************************/
//双向链表的实现
#include <stdio.h>
#include <stdlib.h>
//定义双向链表中的节点
typedef struct node{
int data; //节点的数据域
struct node *p_next;//下一个节点的位置
struct node *p_pre;//前一个结点的位置
}Node;
static Node head, tail; //虚构头尾节点
//初始化链表
void init(){
head.p_next = &tail;//将尾节点“挂”在头节点后面
tail.p_pre = &head;//将头节点“挂”在尾节点前面
}
//清空链表
void deinit(){
while (head.p_next != &tail){
Node *p_node = head.p_next;//将节点“挂”在头节点后面,形成第一个有效数据元素
head.p_next = head.p_next->p_next;//删除第一个有效节点
p_node->p_next->p_pre = &head;//将删除后的第一个有效节点和头节点相连
free(p_node); //释放已经删除的节点空间
p_node = NULL;//防止释放后的野指针
}
}
//从链表头部插入节点
void insert_head(int num){
Node *p_node = (Node *)malloc(sizeof(Node));//动态分配内存一个新节点
if (!p_node){ //处理动态内存分配失败的情况
perror("malloc1");
return;
}
p_node->data = num;//将值赋给新节点
head.p_next->p_pre = p_node;//将新节点“挂”头节点后面
p_node->p_next = head.p_next;//是新节点成为链表的一个节点
p_node->p_pre = &head;//使头节点和新节点项链
head.p_next = p_node;
}
//从尾部插入新节点
void append(int num){
Node *p_node = (Node *)malloc(sizeof(Node));//动态分配一个内存给新节点
if (!p_node){
perror("malloc2");
return;
}
p_node->data = num;//将值赋给新节点;
tail.p_pre->p_next = p_node;//将新节点“挂”在尾部的第一个有效节点上
p_node->p_pre = tail.p_pre;//使新节点和尾节点相连
p_node->p_next = &tail;//将新节点“挂”在尾部
tail.p_pre = p_node;
}
//按顺序插入新节点
void insert_order(int num){
Node *n_node = (Node *)malloc(sizeof(Node));//为新节点动态分配内存
if (!n_node){ //处理动态内存分配失败的情况
perror("malloc3");
return;
}
Node *p_node = NULL;
for (p_node = &head; p_node != &tail; p_node = p_node->p_next){
Node *p_tmp = p_node->p_next;
if ((p_tmp->data) > num || p_tmp == &tail){//插入新节点的情况
n_node->data = num;//将值赋给新节点
n_node->p_pre = p_tmp->p_pre;//将新节点“挂”在指定位置中
p_tmp->p_pre->p_next = n_node;
n_node->p_next = p_tmp;
p_tmp->p_pre = n_node;
break;
}
}
}
//指定插入某节点后面(如果有多个值相同,插入第一个后面)
void insert(int base, int num){
Node *n_node = (Node *)malloc(sizeof(Node));
if (!n_node){ //处理动态内存分配失败的情况
perror("malloc4");
return;
}
Node *p_node = NULL;
for (p_node = &head; p_node != &tail; p_node = p_node->p_next){
Node *p_tmp = p_node->p_next;
if ((p_tmp->data) == base){//找到基准位置
n_node->data = num;//将值赋给新节点
n_node->p_next = p_tmp->p_next;//将新节点“挂”在基准点后面
p_tmp->p_next->p_pre = n_node;//使新节点和基准点相连接
n_node->p_pre = p_tmp;
p_tmp->p_next = n_node;
return;
}
}
//处理基准点不存在的情况
printf("值为%d的节点不存在!无法将值为值%d的节点插入其后。\n", base, num);
free(n_node);
n_node = NULL;
}
//删除第一个有效节点
void delete_head(){
if (head.p_next != &tail){
Node *p_node = head.p_next;
head.p_next = head.p_next->p_next;//将第一个有效节点删除
p_node->p_next->p_pre = &head;//使删除后的节点相连
free(p_node);
p_node = NULL;
}
}
//删除最后一个有效节点
void delete_tail(){
if (tail.p_pre != &head){
Node *p_node = tail.p_pre;
tail.p_pre = tail.p_pre->p_pre;//将最后一个有效节点删除
p_node->p_pre->p_next = &tail;//使删除后的节点相连
free(p_node); //释放删除后的节点空间
p_node = NULL;
}
}
//删除指定节点
void delete(int num){
Node *p_node = NULL;
for (p_node = &head; p_node != &tail; p_node = p_node->p_next){
Node *p_tmp = p_node->p_next;
if (p_tmp != &tail && (p_tmp->data) == num){//找到要删除的节点位置
p_node->p_next = p_tmp->p_next;//删除指定的节点
p_tmp->p_next->p_pre = p_node;//使删除后的节点相连
free(p_tmp); //删除释放后的节点空间
p_tmp = NULL;
break;
}
}
}
//获取链表节点个数
int size(){
int cnt = 0;
Node *p_node = NULL;
//方法一
for (p_node = &head; p_node != &tail; p_node = p_node->p_next){
Node *p_tmp = p_node->p_next;
if (p_tmp != &tail){//判断有效节点的最终位置
cnt++;
}
}
return cnt;
//方法二
/*
for(p_node = &tail; p_node != &head; p_node = p_node -> p_pre){
Node *p_tmp = p_node -> p_pre;
if(p_tmp != &head){
cnt++;
}
}
return cnt;
*/
}
//获取头部节点数据
int first(){
return head.p_next == &tail ? 0 : head.p_next->data;
}
//获取尾部节点数据
int last(){
return tail.p_pre == &head ? 0 : tail.p_pre->data;
}
//顺序打印链表数据
void print_order(){
Node *p_node = NULL;
for (p_node = &head; p_node != &tail; p_node = p_node->p_next){//从头部开始打印节点数据
Node *p_tmp = p_node->p_next;
if (p_tmp != &tail){
printf("%d ", p_tmp->data);
}
}
printf("\n");
}
//逆序打印链表数据
void print_invert(){
Node *p_node = NULL;
for (p_node = &tail; p_node != &head; p_node = p_node->p_pre){//从尾部开始打印节点数据
Node *p_tmp = p_node->p_pre;
if (p_tmp != &head){
printf("%d ", p_tmp->data);
}
}
printf("\n");
}
//读取整数函数
int readInt(){
int value = 0;
while (!scanf("%d", &value)){
scanf("%*[^\n]");//清除缓冲区中的非法换行符
scanf("%*c"); //清除缓冲区中的非法字符
printf("输入有误!请重新输入:");//如果不合法输入,给出提示
}
scanf("%*[^\n]");
scanf("%*c");
return value;
}
int main(void){
init(); //初始化链表
char choice = 'y';//该变量用于让用户选择是否继续操作链表
int tmp = 0; //设置临时变量,用于选择对于链表的操作方式
do{
int num = 0;
printf("请输入一个整数:");//提示输入
num = readInt();
printf("请选择插入的方式,0从头部插入,1从尾部插入,2指定数字后面插入:");//选择操作链表方式
tmp = readInt();//调用readInt函数,读取临时变量的值,从而选定链表操作方式
int base = 0;
switch (tmp){
case 0:
insert_head(num);//在头部插入数据
break;
case 1:
append(num); //在尾部插入数据
break;
case 2:
printf("请输入指定数字:");
base = readInt();
insert(base, num);//指定位置插入数据,其中base为链表中的基准点,num是要插入在base后面的新节点
break;
default: //错误处理
printf("无此种方式!\n");
break;
}
printf("是否继续?输入y继续,否则停止:");//提示是否继续操作链表
scanf("%c", &choice);
} while (choice == 'y' || choice == 'Y');//循环条件
printf("有效元素个数%d\n", size());//检查输入的元素个数
printf("首元素:%d,尾元素:%d\n", first(), last());//查看头尾节点
tmp = 0;
printf("请选择输出方式,0代表顺序输出链表数据,1代表逆序输出链表数据:");//提示选择双向链表的打印方式
tmp = readInt();//调用readInt函数,从而选定输出方式
switch (tmp){
case 0:
print_order();//顺序输出链表元素
break;
case 1:
print_invert();//逆序输出链表元素
break;
default: //错误处理
printf("无此种方式!\n");
break;
}
printf("是否要删除节点?输入y删除,否则不删除:");//选择是否对链表进行删除操作
scanf("%c", &choice);//读入用户选择
if (choice == 'y' || choice == 'Y'){//如果选择删除,则进行下面操作
char ch = 'y';
do{
printf("请选择删除方式,0代表从头部删除,1代表从尾部删除,2代表指定数字删除:");//选择删除方式
tmp = readInt();//读取用户选择
int num = 0;
switch (tmp){
case 0:
delete_head();//从头部删除
break;
case 1:
delete_tail();//从尾部删除
break;
case 2:
printf("请输入要删除的数:");
num = readInt();
delete(num); //指定位置删除
break;
default: //错误处理
printf("无此种方式!\n");
break;
}
printf("是否继续删除?输入y继续,否则停止:");//让用户选择是否继续操作链表
scanf("%c", &ch);//读取用户选择
} while (ch == 'y' || ch == 'Y');
}
printf("请选择输出方式,0代表顺序输出链表数据,1代表逆序输出链表数据:");//再次选择输出链表数据
tmp = readInt();//读取用户选择
switch (tmp){
case 0:
print_order();//顺序输出链表数据
break;
case 1:
print_invert();//逆序输出链表数据
break;
default: //错误处理
printf("无此种方式!\n");
break;
}
deinit(); //清空链表
return 0;
}
运行结果演示: