博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
知识点总结报告 1.25
阅读量:7020 次
发布时间:2019-06-28

本文共 9075 字,大约阅读时间需要 30 分钟。

知识点:链表

链表是一种动态数据结构,相较于数组,具有节省内存空间的作用,但链表在内存中的地址不一定是连续的。链表有单向链表,双向链表以及环形链表等,今天总结单向链表。

单项链表包含一个数据域和一个指针域。在定义结构体时不能嵌套结构体本身但可以包含指向本结构体的指针。这是因为指针的长度都是四个字节不受指向类型限制。指针域用于指向下一个链表的地址,头指针很重要,如果丢失了那么整个链表都会丢失。尾部的节点指针置空。

单向链表的操作有三种:1、建立2、删除、3、插入

链表的定义:struct link

{

  int data;

  struck link *next;

}

建立一个单向链表(可自由添加节点):

1 #include 
2 #include
3 #include
4 struct link *AppendNode(struct link *head);//创建并链接节点,返回头指针 5 void DisplayNode(struct link *head);//用于展示链表的数据域和链表的序号 6 void DeleteMemory(struct link *head);//释放内存 7 struct link //构造一个链表 8 { 9 int data;10 struct link *next;11 };12 int main()13 {14 int i=0;15 char c,d;16 int nodeData=0;17 struct link *head=NULL;18 printf("Do you want to append a new node?(Y/y)or(N/n)\n");19 scanf(" %c",&c);20 while(c=='Y' || c=='y')21 {22 head = AppendNode(head);23 DisplayNode(head);24 printf("Do you want to append a new node?(Y/y)or(N/n)\n");25 scanf(" %c",&c);26 i++;27 }28 printf("%d new Node have been appended\n",i);29 DeleteMemory(head);30 return 0;31 }32 33 34 struct link *AppendNode(struct link *head)35 {36 struct link *p=NULL,*pr=head;//37 p=(struct link *)malloc(sizeof(struct link));38 if(p==NULL)39 {40 printf("no enough memory!\n");41 exit(0);42 }43 if(head==NULL)//如果没有头节点,那么p充当头节点44 {45 head=p;46 }47 else48 {49 while(pr->next!=NULL)//指向类型为struct link的指针pr一直移动到表尾50 {51 pr=pr->next;52 }53 pr->next=p;//如果有了有节点,那么p作为表尾54 }55 printf("Input node data\n");56 scanf("%d",&p->data);57 p->next=NULL;//表尾指针域置空58 return head;59 }60 61 void DisplayNode(struct link *head)62 {63 int i=0;64 struct link *p;65 p=head;66 while(p!=NULL)67 {68 i++;69 printf("%-4d%-5d\n",i,p->data);//展示当前节点的序号和数据70 p=p->next;//指向下一个71 }72 }

单向链表的删除操作:

要删除一个节点需要考虑四种情况:

1、链表为空表 那么无需删除节点直接退出程序

2、链表非空,删除头节点  则将头节点的指针域赋值给头指针 head=p->next;然后p->next置空

3、删除中间结点  p指向当前要删除的节点,pr指向上一个节点那么pr->next=p->next;   p->next置空

4、删除尾节点  pr-next=p->next 或者 pr->next=NULL.    

以上节点置空操作可要可不要,因为在其上一步操作完成后这个节点已经被断开了。

根据以上编程思想,实现节点删除操作的函数可以写成:

1 struct link *DeleteNode(struct link *head,int nodeData) 2 { 3     struct link *p=head,*pr=head; 4     if(head==NULL) 5     { 6         printf("Linked table is empty!\n"); 7         return head; 8     } 9     while(p->data!=nodeData && p->next!=NULL)//如果没有找到数据,就把指针往下一个节点移10     {11         pr=p;12         p=p->next;13     }14     if(p->data==nodeData)15     {16         if(head==p)//如果删除的是头节点17         {18             head=p->next;19             p->next=NULL;20         }21         else//如果删除掉的是中间节点或者尾节点(尾节点:如果一直没找到对应节点那么指针p会在while内一直后移直到移动到尾节点)22         {23             pr=p->next;24             p->next=NULL;25         }26         free(p);//释放指针p指向的被删除节点的内存27     }28     else29     {30         printf("This Node has not been found!\n");//如果数据不在链表里31     }32     return head;33 };

 单向链表的插入操作:

插入节点时,首先用结构指针p指向动态内存函数申请的一个空间,并置空指针域。链表的插入有四个不同的位置,因此要分四种情况。

1、链表为空   此时直接将该节点作为头节点,让head指向头节点 head=p;

2、链表的为空,插入的节点在头指针和头节点之间   首先将原head指向的节点用p的指针域指向,p->next=head;然后head指向节点p,head=p;

3、插入的节点在中间   将新节点的指针域指向后面一个节点,p->next=pr-next;  然后将上一个节点的指针域指向新节点,pr->next=p;

4、加入的节点在表尾   将上一节点的指针域指向新节点即可,pr->next=p;

根据上面的思想写出的函数:

1 struct link *InsterNode(struct link* head,int nodeData)//根据数据插入节点 2 { 3     struct link *p=NULL,*pr=head,*temp=NULL; 4     p=(struct link *)malloc(sizeof(struct link)); 5     if(p==NULL) 6     { 7         printf("There is no enough memory!\n"); 8         exit(0); 9     }10     p->data=nodeData;//申请内存成功之后,添加数据域,开始插入11     p->next=NULL;12     if(head==NULL)13     {14         head=p;15         p->next=NULL;16     }17     while(pr->data
next!=NULL)//按升序的规范插入节点18 {19 temp=pr;//临时指针的作用20 pr=pr->next;21 }22 if(pr->data>=nodeData)23 {24 if(head==pr)//如果链表为空25 {26 p->next=pr;27 head=p;28 }29 else30 {31 temp->next=p;//在头指针和头节点之间插入节点以及在链表中间插入节点32 p->next=pr;33 }34 }35 else36 {37 pr->next=p;//在表尾插入节点38 }39 return head;40 };

一个完整的C程序:

1 #include 
2 #include
3 #include
4 struct link *AppendNode(struct link *head);//创建并链接节点,返回头指针 5 void DisplayNode(struct link *head);//用于展示链表的数据域和链表的序号 6 void DeleteMemory(struct link *head);//释放内存 7 struct link *DeleteNode(struct link *head,int nodeData);//根据数据删除节点 8 struct link *InsterNode(struct link *head,int nodeData);//根据数据插入节点 9 struct link //构造一个链表 10 { 11 int data; 12 struct link *next; 13 }; 14 int main() 15 { 16 int i=0; 17 char c,d,e; 18 int nodeData=0; 19 struct link *head=NULL; 20 printf("Do you want to append a new node?(Y/y)or(N/n)\n"); 21 scanf(" %c",&c); 22 while(c=='Y' || c=='y') 23 { 24 head = AppendNode(head); 25 DisplayNode(head); 26 printf("Do you want to append a new node?(Y/y)or(N/n)\n"); 27 scanf(" %c",&c); 28 i++; 29 } 30 printf("Do you want to delete a node?(Y/y)or(N/n)\n"); 31 scanf(" %c",&d); 32 while(d=='Y' || d=='y') 33 { 34 printf("Input data you want to delete\n"); 35 scanf(" %d",&nodeData); 36 head=DeleteNode(head,nodeData); 37 DisplayNode(head); 38 printf("Do you want to delete a node?(Y/y)or(N/n)\n"); 39 scanf(" %c",&d); 40 } 41 printf("Do you want to inster a new node?(Y/y)or(N/n)\n"); 42 scanf(" %c",&e); 43 while(e=='Y' || e=='y') 44 { 45 printf("Input data you want to inster\n"); 46 scanf("%d",&nodeData); 47 head=InsterNode(head,nodeData); 48 DisplayNode(head); 49 printf("Do you want to inster a new node?(Y/y)or(N/n)\n"); 50 scanf(" %c",&e); 51 } 52 printf("%d new Node have been appended\n",i); 53 DeleteMemory(head); 54 return 0; 55 } 56 57 58 struct link *AppendNode(struct link *head) 59 { 60 struct link *p=NULL,*pr=head;// 61 p=(struct link *)malloc(sizeof(struct link)); 62 if(p==NULL) 63 { 64 printf("no enough memory!\n"); 65 exit(0); 66 } 67 if(head==NULL)//如果没有头节点,那么p充当头节点 68 { 69 head=p; 70 } 71 else 72 { 73 while(pr->next!=NULL)//指向类型为struct link的指针pr一直移动到表尾 74 { 75 pr=pr->next; 76 } 77 pr->next=p;//如果有了有节点,那么p作为表尾 78 } 79 printf("Input node data\n"); 80 scanf("%d",&p->data); 81 p->next=NULL;//表尾指针域置空 82 return head; 83 } 84 85 void DisplayNode(struct link *head) 86 { 87 int i=1; 88 struct link *p=head; 89 while(p!=NULL) 90 { 91 printf("%-4d%-5d\n",i,p->data);//展示当前节点的序号和数据 92 p=p->next;//指向下一个 93 i++; 94 } 95 } 96 97 void DeleteMemory(struct link *head) 98 { 99 struct link *p,*pr;100 p=head;101 while(p!=NULL)102 {103 pr=p;//让pr保存当前节点104 p=p->next;//p指向下一节点105 free(pr);//释放申请的内存106 }107 }108 109 struct link *DeleteNode(struct link *head,int nodeData)110 {111 struct link *p=head,*pr=head;112 if(head==NULL)113 {114 printf("Linked table is empty!\n");115 return (head);116 }117 while(p->data!=nodeData && p->next!=NULL)//如果没有找到数据,就把指针往下一个节点移118 {119 pr=p;120 p=p->next;121 }122 if(p->data==nodeData)123 {124 if(head==p)//如果删除的是头节点125 {126 head=p->next;127 p->next=NULL;128 }129 else//如果删除掉的是中间节点或者尾节点(尾节点:如果一直没找到对应节点那么指针p会在while内一直后移直到移动到尾节点)130 {131 pr->next=p->next;132 p->next=NULL;133 }134 free(p);//释放指针p指向的被删除节点的内存135 }136 else137 {138 printf("This Node has not been found!\n");//如果数据不在链表里139 }140 return head;141 };142 143 struct link *InsterNode(struct link* head,int nodeData)144 {145 struct link *p=NULL,*pr=head,*temp=NULL;146 p=(struct link *)malloc(sizeof(struct link));147 if(p==NULL)148 {149 printf("There is no enough memory!\n");150 exit(0);151 }152 p->data=nodeData;//申请内存成功之后,添加数据域,开始插入153 p->next=NULL;154 if(head==NULL)155 {156 head=p;157 p->next=NULL;158 }159 while(pr->data
next!=NULL)//按升序的规范插入节点160 {161 temp=pr;//临时指针的作用162 pr=pr->next;163 }164 if(pr->data>=nodeData)165 {166 if(head==pr)//如果链表为空167 {168 p->next=pr;169 head=p;170 }171 else172 {173 temp->next=p;//在头指针和头节点之间插入节点以及在链表中间插入节点174 p->next=pr;175 }176 }177 else178 {179 pr->next=p;//在表尾插入节点180 }181 return head;182 };

 不过程序容错性差,如果不小心在该按下Y/y/R/的时候按错了可能会造成后果。

 

转载于:https://www.cnblogs.com/desier/p/8353797.html

你可能感兴趣的文章
spark写mysql优化简书_Spark SQL:性能优化
查看>>
mysql gtid 主主_MySQL优化之七--Mysql基于GTID的主从复制
查看>>
python字节码文件后缀_Python反编译之字节码
查看>>
gdb加载python_gdb加载python脚本的方法
查看>>
let 指定长度的数组_怎样在JavaScript中创建和填充任意长度的数组 [每日前端夜话0x29]...
查看>>
python格式化转换_Python进制转换format格式化
查看>>
清理mysql空间不足_清理MySQL bin-log 日志过大,解决空间不足
查看>>
java hashmap 异步_基于HashMap多线程并发问题分析
查看>>
java 移动目录_使用Java将文件从一个目录移动到另一个目录 - Break易站
查看>>
java arraylist 字符串_java – 字符串的ArrayList到一个字符串
查看>>
mysql 慢查询 测试_MYSQL慢查询与日志的设置与测试
查看>>
mysql 特殊运算_MySql中特殊运算符的使用方法总结
查看>>
mysql语句转化longbob编码_如何写出优雅的代码?
查看>>
java timsort_JDK(二)JDK1.8源码分析【排序】timsort
查看>>
java 如何调用存储过程_Java中存储过程的调用
查看>>
java偏好设置_Linux中不同用户下的Java系统偏好设置
查看>>
java种线程池多线程有返回值_Java多线程-新特性-有返回值的线程
查看>>
java axis2小实例_[图解教程] Axis2与Eclipse整合开发Web Service之一:简单的计算服务例子...
查看>>
java hashmap比较_Java中对HashMap的深度分析与比较
查看>>
Java季度半年_java获取当前年、半年、季度、月、日、小时 开始结束时间等
查看>>