数据结构——双向链表(C语言实现)
来源:互联网 发布:js语言精粹怎么样 编辑:程序博客网 时间:2024/04/26 08:25
/*************************************************************************> 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;}
运行结果演示:
0 0
- 数据结构C语言实现系列——双向链表
- 数据结构——双向链表(C语言实现)
- C语言数据结构2——双向链表的实现
- 数据结构——双向链表(C语言)
- (C语言)双向链表实现案例(数据结构六)
- 数据结构--双向循环链表c语言实现
- 数据结构之---c语言实现双向链表操作
- 数据结构之双向链表(C语言实现)
- C语言数据结构之双向链表
- C语言数据结构----双向链表
- C 语言 数据结构之双向链表
- 数据结构(C实现)------- 双向链表
- C实现通用数据结构--双向链表
- 数据结构--双向循环链表C实现
- 数据结构双向链表c语言实现(linux下多文件实现)
- C语言基础—数据结构之单向循环链表和双向循环链表
- 数据结构与算法(C语言描述)——双向链表
- 数据结构——c语言描述 第二章(3) 双向链表
- Javascript 使用Hashmap/Dict 和陷阱
- 谈一下我的博客
- 包
- 6--内存管理
- iOS基础:获取资源文件的方法
- 数据结构——双向链表(C语言实现)
- CADisplayLink(主) 和 NSTimer
- Qt 基础:QEvent
- 凯撒密码
- Android之RadioGroup+ViewPager制作的底部导航栏
- GO语言编程-顺序编程之变量
- Windows下Anaconda的安装和简单使用
- VC++的Unicode编程
- Javascript 将鼠标的光标停留在文字的最后