知识点总结报告 1.25
知识点:链表
链表是一种动态数据结构,相较于数组,具有节省内存空间的作用,但链表在内存中的地址不一定是连续的。链表有单向链表,双向链表以及环形链表等,今天总结单向链表。
单项链表包含一个数据域和一个指针域。在定义结构体时不能嵌套结构体本身但可以包含指向本结构体的指针。这是因为指针的长度都是四个字节不受指向类型限制。指针域用于指向下一个链表的地址,头指针很重要,如果丢失了那么整个链表都会丢失。尾部的节点指针置空。
单向链表的操作有三种:1、建立2、删除、3、插入
链表的定义:struct link
{
int data;
struck link *next;
}
建立一个单向链表(可自由添加节点):
1 #include <stdio.h> 2 #include <stdio.h> 3 #include <malloc.h> 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 else 48 { 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 else 29 { 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<nodeData && pr->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 else 30 { 31 temp->next=p;//在头指针和头节点之间插入节点以及在链表中间插入节点 32 p->next=pr; 33 } 34 } 35 else 36 { 37 pr->next=p;//在表尾插入节点 38 } 39 return head; 40 };
一个完整的C程序:
1 #include <stdio.h> 2 #include <stdio.h> 3 #include <malloc.h> 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 else 137 { 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<nodeData && pr->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 else 172 { 173 temp->next=p;//在头指针和头节点之间插入节点以及在链表中间插入节点 174 p->next=pr; 175 } 176 } 177 else 178 { 179 pr->next=p;//在表尾插入节点 180 } 181 return head; 182 };
不过程序容错性差,如果不小心在该按下Y/y/R/的时候按错了可能会造成后果。