[数据结构与算法] 单链表的简单demo
Vc6之下编译通过。。
1 /******************************************************* 2 * @: Project: 单链表数据结构演示 3 * @: File: link_list.h 4 * @: Function: 提供单链表操作的数据结构定义及方法声明 5 * @: History: 2013-10-01 22:37:05 6 * @: Author: Alimy 7 *******************************************************/ 8 /******************************************************* 9 * @:头文件包含 10 *******************************************************/ 11 12 #ifndef __LINK_LIST_H__ 13 #define __LINK_LIST_H__ 14 /******************************************* 15 * @: 数据结构定义&一些宏 16 ********************************************/ 17 #define ElemType signed short int // 此例子中的数据为有符号短整形,在VC6 中占据16bits 18 #define StatusType int //操作状态为int类型 19 #define OK (StatusType)1 20 #define ERROR (StatusType)0 21 22 typedef struct LNode{ 23 ElemType m_data; // 数据域 24 struct LNode *p_next; // 指针域 25 } LNode, *pLinkList; 26 27 //typedef struct LHead{ //头结点,其实和 LNode的内存结构相似, 28 // int ElemNumber; //数据域,可以存储当前线性表的长度,也可以什么也不存储 29 // struct LNode *p_FirstNode; //指针域指向线性表的第一个元素 30 //}LHead, *pLHead; 31 32 #define DATA_FIELD 0//定义是否让头结点的数据域存储表长信息 1为存储(头结点模式),0为不存储(非头结点模式) 33 34 /******************************************* 35 * @: 外部调用函数声明 36 ********************************************/ 37 extern StatusType CreateList_L(pLinkList *pL,int num);//构造num个结点的单链表 38 //extern StatusType _CreateList_L(pLinkList *pL,int num); 39 extern StatusType GetElem_L(pLinkList *pL,int idx_location, ElemType* pe); //获取单链表的元素 40 extern StatusType InsertElem_L(pLinkList *pL,int idx_location,ElemType e);//在单链表中插入元素 41 extern StatusType DeleteElem_L(pLinkList *pL,int idx_location,ElemType* pe);//在单链表中删除元素 42 extern void ClearList_L(pLinkList *pL); //整表删除 43 extern int LocateElem_L(pLinkList *pL,ElemType e); //定位元素 44 extern int GetLength_L(pLinkList *pL); 45 46 extern void MergeList_L1(pLinkList *pLa,pLinkList *pLb,pLinkList *pLc);//将两个有序链表并为一个有序链表 47 extern void MergeList_L2(pLinkList *pLa,pLinkList *pLb,pLinkList *pLc);//将两个有序链表并为一个有序链表 48 49 50 extern void DisplayList_L(pLinkList *pL); //显示当前所有单链表的长度 51 #endif // end of __LINK_LIST_H__
1 /******************************************************* 2 * @: Project: 单链表数据结构演示 3 * @: File: link_list.c 4 * @: Function: 提供单链表操作的基本函数和方法 5 * @: History: 2013-10-01 22:37:37 6 * @: Author: Alimy 7 *******************************************************/ 8 9 /******************************************************* 10 * @: 头文件包含 11 *******************************************************/ 12 #include "link_list.h" 13 #include <stdio.h> 14 #include <conio.h> // int getch(void); 15 #include <stdlib.h> // int rand(void); malloc(); free(); 16 #include <time.h> // time_t time(time_t *); 17 18 /******************************************************* 19 * @: (外部&内部)变量声明及定义 20 *******************************************************/ 21 22 /******************************************************* 23 * @: (外部&内部)函数声明及定义 24 *******************************************************/ 25 StatusType CreateList_L(pLinkList *pL,int num);//构造num个结点的单链表 26 StatusType GetElem_L(pLinkList *pL,int idx_location, ElemType* pe); //获取单链表的元素 27 StatusType InsertElem_L(pLinkList *pL,int idx_location,ElemType e);//在单链表中插入元素 28 StatusType DeleteElem_L(pLinkList *pL,int idx_location,ElemType* pe);//在单链表中删除元素 29 int LocateElem_L(pLinkList *pL,ElemType e); //定位元素 30 int GetLength_L(pLinkList *pL);//获得表长 31 void ClearList_L(pLinkList *pL); //整表删除 32 33 void DisplayList_L(pLinkList *pL); //显示当前所有单链表的长度 34 35 36 37 38 39 40 /******************************************************* 41 * @: 内部函数具体实现 42 *******************************************************/ 43 44 //ElemType s_data[] = {1,2,3,4,5,6,7,8,9,10,11}; 45 46 /* 47 *@:在堆中构造一个单链表,并逆序插入num个结点(头插法) 48 *@:返回值 49 *@: 构造成功返回OK 50 *@: 构造失败返回ERROR 51 **/ 52 StatusType CreateList_L(pLinkList *pL,int num){//构造num个结点的单链表 53 LNode* p_Work = NULL; //工作指针 54 int idx = 0; 55 if(*pL!=NULL){ 56 printf("当前单链表已被初始化,不需要执行Create操作 \n"); 57 return ERROR; 58 } 59 60 *pL = (pLinkList)malloc(sizeof(LNode)); 61 if(*pL == NULL){ 62 printf("在堆中申请头结点失败 \n"); 63 return ERROR; 64 } 65 (*pL)->m_data = 0; // 数据域可以存储当前单链表的长度 66 (*pL)->p_next = NULL; 67 68 srand(time(0)); 69 for(idx=0;idx<num;idx++){ 70 p_Work = (pLinkList)malloc(sizeof(LNode)); //在堆中申请新的结点 71 if(p_Work==NULL){ 72 printf("在堆中申请结点出现异常,构造单链表失败 \n"); 73 return ERROR; 74 } 75 76 //p_Work->m_data = 10*s_data[idx%10];//(rand()%(10)); //均为10以内的整数 77 p_Work->m_data = (rand()%(100))+1; //晕死,每次生产的随机数怎么都一样 78 p_Work->p_next = (*pL)->p_next; 79 (*pL)->p_next = p_Work; //逆序插入,第一个产生为表尾 80 } 81 82 (*pL)->m_data = num; 83 84 // printf("构造单链表成功,单链表的当前长度为 【%d】 \n",(*pL)->m_data); 85 // printf("单链表的元素值依次是 \n"); 86 // p_Work = (*pL); //指向头结点 87 // idx = 0; 88 // while(p_Work->p_next){// p_ Work->p_next != NULL 89 // idx++; 90 // p_Work = p_Work->p_next; 91 // printf("单链表的第【%d】个元素的值为【%d】\n",idx,p_Work->m_data); 92 93 // } 94 printf("构造含【%d】个元素的单链表成功,按任意键去到主菜单\n",(*pL)->m_data); 95 getch(); 96 return OK; 97 } 98 //StatusType _CreateList_L(pLinkList *pL,int num){//构造num个结点的单链表(尾插法) 99 // LNode* p_Work = NULL; 100 // LNode* p_NewNode = NULL; //指向新申请结点 101 // LNode* p_LastNode = NULL; //指向当前单链表的最后一个结点 102 // int idx = 0; 103 // if(*pL!=NULL){ 104 // printf("当前单链表已被初始化,不需要执行Create操作 \n"); 105 // return ERROR; 106 // } 107 // 108 // *pL = (pLinkList)malloc(sizeof(LNode));//(建立头结点) 109 // if(*pL == NULL){ 110 // if(*pL == NULL){ 111 // printf("在堆中申请头结点失败 \n"); 112 // return ERROR; 113 // } 114 // 115 // } 116 // (*pL)->m_data = 0; // 数据域可以存储当前单链表的长度 117 // (*pL)->p_next = NULL; 118 // p_LastNode = (*pL); 119 // srand(time(0)); 120 // for(idx=0;idx<num;idx++){ 121 // p_NewNode = (LNode*)malloc(sizeof(LNode)); 122 // if(p_NewNode == NULL){ 123 // printf("在堆中申请新结点失败 \n"); 124 // return ERROR; 125 // } 126 // p_NewNode->m_data = (rand()%(10)); 127 // p_NewNode->p_next = NULL; 128 // p_LastNode->p_next = p_NewNode; 129 // p_LastNode = p_NewNode; 130 // } 131 // 132 // (*pL)->m_data = num; 133 // 134 // printf("构造单链表成功,单链表的当前长度为 【%d】 \n",(*pL)->m_data); 135 // printf("单链表的元素值依次是 \n"); 136 // 137 // p_Work = (*pL); //指向头结点 138 // idx = 0; 139 // while(p_Work->p_next){// p_ Work->p_next != NULL 140 // idx++; 141 // p_Work = p_Work->p_next; 142 // printf("单链表的第【%d】个元素的值为【%d】\n",idx,p_Work->m_data); 143 // } 144 // printf("构造含【%d】个元素的单链表成功,按任意键去到主菜单",(*pL)->m_data); 145 // getch(); 146 // return OK; 147 //} 148 149 150 151 /* 152 *@:定位pL指向的单链表的第idx_location 个元素,并将该元素的值赋值给pe指向的内存 153 *@:返回值 154 *@: 定位数据成功返回OK 155 *@: 定位数据失败返回ERROR 156 **/ 157 StatusType GetElem_L(pLinkList *pL,int idx_location, ElemType* pe){ //获取单链表的元素 158 int idx = 0; 159 LNode * p_Work = NULL; // 工作指针 160 161 #if DATA_FIELD == 0 162 p_Work = (*pL); //工作指针指向头指针 163 idx = 0; 164 while(p_Work && idx<idx_location){ // 移动工作指针&计数判断是否有 165 p_Work = p_Work->p_next; 166 idx++; 167 // p_Work 指向第idx个结点 168 } 169 170 if((!p_Work)||(idx>idx_location)){ 171 // printf("索引数据有(非头结点模式)\n"); 172 return ERROR; 173 } 174 175 *pe = p_Work->m_data; 176 return OK; 177 #else 178 //若头结点的数据域存储了单链表的表长信息 179 if((idx_location>(*pL)->m_data)||(idx_location<1)){ //索引有误 180 // printf("索引数据有误(头结点模式) \n"); 181 return ERROR; 182 } 183 p_Work = (*pL); 184 idx = 0; //工作指针指向头结点,计数清零 185 for(;idx<idx_location;){ 186 p_Work = p_Work->p_next; 187 idx++; 188 } 189 //此时p_Work指向第idx_location个结点 190 *pe = p_Work->m_data; 191 return OK; 192 #endif 193 194 } 195 196 197 198 /* 199 *@:在pL指向的单链表的第idx_location 个位置插入值为e的元素 200 *@:返回值 201 *@: 插入元素成功返回OK 202 *@: 插入元素失败返回ERROR 203 *@: 时间复杂度:O(n) 但是插入一个和插入N个区别不多,单链表适合(比较顺序表)插入操作较频繁的操作 204 205 **/ 206 StatusType InsertElem_L(pLinkList *pL,int idx_location,ElemType e){//在单链表中插入元素 207 208 int idx = 0; 209 LNode* p_Work = NULL; 210 LNode* pNewNode = NULL; 211 212 #if DATA_FIELD == 0 213 // to do 2013-10-06 00:10:46 214 p_Work = (*pL); //工作指针指向头结点 215 idx = 0; 216 217 while((p_Work)&&(idx<idx_location-1)){ 218 idx++; 219 p_Work = p_Work->p_next; 220 } 221 //正常情况下,p_Work应该指向第【idx_location - 1】个元素 222 if((!p_Work)||(idx>idx_location-1)){ 223 printf("要插入元素的索引有误,请检查后重新输入 \n"); 224 return ERROR; 225 } 226 else{ 227 pNewNode = (LNode *)malloc(sizeof(LNode)); 228 if(!pNewNode){ 229 printf("在插入元素时,申请堆空间失败,插入操作元素失败 \n"); 230 return ERROR; 231 } 232 else{ 233 pNewNode->m_data = e; 234 pNewNode->p_next = p_Work->p_next; 235 p_Work->p_next = pNewNode; 236 return OK; 237 } 238 239 240 } 241 #else 242 //头结点存储了单链表的长度 243 if((idx_location<1)||(idx_location>(*pL)->m_data+1)){ // 元素索引逻辑有误 244 printf("要插入元素的索引有误,请检查后重新输入 \n"); 245 return ERROR; 246 } 247 else{ 248 p_Work = (*pL); 249 idx = 0; //工作指针指向头结点,计数清零 250 for(;idx<idx_location-1;){ 251 p_Work = p_Work->p_next; 252 idx++; 253 } 254 // p_Work指向第【idx_location-1】个结点 255 pNewNode = (LNode *)malloc(sizeof(LNode)); 256 if(!pNewNode){ 257 printf("在插入元素时,申请堆空间失败,插入操作元素失败 \n"); 258 return ERROR; 259 } 260 else{ 261 pNewNode->m_data = e; 262 pNewNode->p_next = p_Work->p_next; 263 p_Work->p_next = pNewNode; // s->next = p->next; p->next = s; 264 (*pL)->m_data++; //计数器自加 265 printf("插入元素成功\n"); 266 return OK; 267 } 268 } 269 #endif 270 } 271 272 273 /* 274 *@:在pL指向的单链表中寻找第一个值为e的元素,将其索引返回 275 *@: 返回值 276 * 找到值为e的元素--->返回非0 索引值 277 * 没有找到----> 返回0 278 */ 279 int LocateElem_L(pLinkList *pL,ElemType e){ //定位元素 280 int idx = 0; 281 LNode * p_Work = NULL; 282 if(*pL==NULL){ 283 printf("当前单链表未被初始化,无法执行定位操作 \n"); 284 return 0; 285 } 286 287 p_Work = (*pL); 288 idx = 0; //计数清零,工作指针指向头结点 289 //_Loops: 290 // if(p_Work->p_next!=NULL) 291 // { 292 // p_Work = p_Work->next; 293 // idx++; 294 // if(p_Work->m_data == e) 295 // return idx; 296 // goto _Loops; 297 // } 298 299 while(p_Work->p_next!=NULL){ 300 p_Work = p_Work->p_next; 301 idx++; 302 if(p_Work->m_data == e){ 303 printf("找到单链表的第【%d】个元素的值为【%d】",idx,p_Work->m_data); 304 return idx; 305 } 306 } 307 printf("没有定位到元素"); 308 return 0; // 上述没有定位到 309 310 311 } 312 313 /* 314 *@:删除pL指向的单链表的第idx_location 个位置的元素,并将被删除结点的数据域赋值给pe指向的内存 315 *@:返回值 316 *@: 删除元素成功返回OK 317 *@: 删除元素失败返回ERROR 318 *@: 时间复杂度:O(n) 但是删除一个和删除N个区别不多,单链表适合(比较顺序表)删除操作较频繁的操作 319 **/ 320 StatusType DeleteElem_L(pLinkList *pL,int idx_location,ElemType* pe){//在单链表中删除元素 321 int idx = 0; 322 LNode * p_Work = NULL; 323 LNode * p_Temp = NULL; 324 325 #if DATA_FIELD == 0 326 idx = 0; 327 p_Work = (*pL); //工作指针指向头结点 328 while((p_Work)&&(idx<idx_location-1)){ 329 idx++; 330 p_Work = p_Work->p_next; 331 } 332 //正常情况下,p_Work应该指向第【idx_location - 1】个元素 333 if((!p_Work)||(idx>idx_location-1)){ 334 printf("要删除位置的索引有误,请重新输入 \n"); 335 return ERROR; 336 } 337 else{ 338 p_Temp = p_Work->p_next; //指向要删除的结点 339 p_Work->p_next = p_Temp->p_next;//p_Work->p_next = p_Work->p_next->p_next; 340 *pe = p_Temp->m_data; 341 free(p_Temp); 342 return OK; 343 } 344 #else 345 if((idx_location<1)||(idx_location>(*pL)->m_data)){ // 346 printf("要删除元素位置索引有误,请检查输入 \n"); 347 return ERROR; 348 } 349 else{ 350 p_Work = (*pL); 351 idx = 0; //工作指针指向头结点 352 for(;idx<idx_location-1;){ 353 p_Work = p_Work->p_next; 354 idx++; 355 } 356 //p_Work指向第【idx_location - 1 】个结点 357 p_Temp = p_Work->p_next; 358 p_Work->p_next = p_Temp->p_next;//p_Work->p_next = p_Work->p_next->p_next; 359 *pe = p_Temp->m_data; 360 free(p_Temp); 361 (*pL)->m_data--; 362 return OK; 363 } 364 365 #endif 366 } 367 368 /* 369 * @:获取pL指向的单链表中的元素个数 370 * @:返回值 371 * 得到长度--->返回非0长度值 372 * 得不到长度---->返回0 373 */ 374 int GetLength_L(pLinkList *pL){//获得表长 375 376 int idx = 0; 377 LNode * p_Work = NULL; 378 if(*pL==NULL){ 379 printf("当前单链表未被初始化,无法获取表长\n"); 380 return 0; 381 } 382 #if DATA_FIELD == 0 383 p_Work = (*pL); 384 idx = 0; //计数清零,工作指针指向头结点 385 while(p_Work->p_next!=NULL){ 386 idx++; 387 p_Work = p_Work->p_next; 388 } 389 printf("当前单链表共有【%d】个元素\n",idx); 390 return idx; 391 392 #else 393 idx = (*pL)->m_data; 394 printf("当前单链表共有【%d】个元素\n",idx); 395 396 return idx; 397 398 399 #endif 400 401 } 402 /* 403 *@:删除pL指向的单链表的所有结点 404 */ 405 406 void ClearList_L(pLinkList *pL){ //整表删除 407 LNode* p_Work1 = NULL; 408 LNode* p_Work2 = NULL; //工作指针 409 410 if(*pL == NULL){ 411 printf("当前单链表未创建,无法执行整表删除操作 \n"); 412 return ; 413 } 414 else if((*pL)->p_next == NULL){ 415 printf("当前单链表为空表,不需要执行整表删除操作 \n"); 416 return; 417 } 418 else{ 419 p_Work1 = (*pL)->p_next; // 指向第一个结点(如果有的话) 420 while(p_Work1!=NULL){ 421 p_Work2 = p_Work1; 422 p_Work1 = p_Work2->p_next;//指向下一个 423 free(p_Work2); 424 } 425 426 // (*pL)->p_next = NULL; // 头结点指向NULL 427 (*pL)->m_data = 0; 428 return ; 429 } 430 } 431 432 /* 433 *@: 输出显示pL指向的单链表所有的元素 434 */ 435 void DisplayList_L(pLinkList *pL){ //显示当前所有单链表的长度 436 437 int idx = 0; 438 LNode* p_Work = NULL; 439 440 if(*pL==NULL){ 441 printf("单链表还未构建,输不出东东 \n"); 442 return ; 443 } 444 445 #if DATA_FIELD == 0 446 idx = 0; 447 p_Work = (*pL); // 工作指针指向头结点,计数清零 448 if(p_Work->p_next==NULL){ 449 printf("当前单链表为空表,没什么东东好显示的 \n"); 450 return ; 451 } 452 else{ 453 while(p_Work->p_next){ //(p_Work->p_next!=NULL) 454 idx++; 455 p_Work = p_Work->p_next; 456 printf("单链表第【%d】个元素的值为【%d】\n",idx,p_Work->m_data); 457 } 458 return ; 459 } 460 #else 461 if((*pL)->m_data == 0){ 462 printf("当前单链表的表长为0,没有数据元素,没有什么好打印的 \n"); 463 return ; 464 } 465 idx = 0; 466 p_Work = (*pL); // 工作指针指向头结点,计数清零 467 printf("单链表数据如下:\n"); 468 for(;idx<(*pL)->m_data;){ // idx < currentLength (currentLength == (*pL)->m_data or currentLength == GetLength_L ) 469 idx++; 470 p_Work = p_Work->p_next; 471 printf("单链表第【%d】个元素的值为【%d】\n",idx,p_Work->m_data); 472 } 473 return ; 474 #endif 475 476 } 477 478 479 480 481 //演示程序中没有用到的程序 482 483 void MergeList_L1(pLinkList *pLa,pLinkList *pLb,pLinkList *pLc);//归并两个单链表 484 /* 485 *@:归并,已知pLa和pLb指向的单链表的元素都按非递减排列 486 * 将La 和Lb中的元素归并到pLc指向的单链表中 487 */ 488 void MergeList_L1(pLinkList *pLa,pLinkList *pLb,pLinkList *pLc){ // 按顺序表的方法新建结点归并到pLc,形成一个新的表,对原来的那两个单链表没有损伤 489 LNode * p_WorkLa = NULL; 490 LNode * p_WorkLb = NULL; 491 int Lc_len = 0; 492 *pLc = (LNode *)malloc(sizeof(LNode)); //*pLc进来是是未被初始化的,即(*pLc) == NULL 493 (*pLc)->m_data = 0; 494 (*pLc)->p_next = NULL; // 将pLc指向空表 495 496 497 p_WorkLa = (*pLa)->p_next; 498 p_WorkLb = (*pLb)->p_next; // 初始化时都指向第一个结点(如果有第一个的话) 499 500 while((p_WorkLa!=NULL)&&(p_WorkLb!=NULL)){ 501 Lc_len++; //一定有可以插入的元素 502 if(p_WorkLa->m_data>=p_WorkLb->m_data){ 503 InsertElem_L(pLc,Lc_len,p_WorkLb->m_data); 504 p_WorkLb = p_WorkLb->p_next; 505 } 506 else{ 507 InsertElem_L(pLc,Lc_len,p_WorkLa->m_data); 508 p_WorkLa = p_WorkLa->p_next; 509 } 510 } 511 512 while(p_WorkLa!=NULL){ 513 Lc_len++; 514 InsertElem_L(pLc,Lc_len,p_WorkLa->m_data); 515 p_WorkLa = p_WorkLa->p_next; 516 } 517 518 while(p_WorkLb!=NULL){ 519 Lc_len++; 520 InsertElem_L(pLc,Lc_len,p_WorkLb->m_data); 521 p_WorkLb = p_WorkLb->p_next; 522 } 523 } 524 525 526 void MergeList_L2(pLinkList *pLa,pLinkList *pLb,pLinkList *pLc){//不新建结点,就用链表把la和lb中的元素用指针连接起来也成为lc的结点 527 LNode* p_la = NULL; 528 LNode* p_lb = NULL; 529 LNode* p_lc = NULL; 530 531 p_la = (*pLa)->p_next; 532 p_lb = (*pLc)->p_next; // 都指向第一个结点 533 534 pLc = p_lc = p_la; //用La的头结点作为Lc的头结点 535 536 while((p_la!=NULL)&&(p_lb!=NULL)){ 537 if(p_la->m_data <= p_lb->m_data){ 538 p_lc->p_next = p_la; 539 p_lc = p_la; // 工作指针移动 540 p_la = p_la->p_next; 541 } 542 else{ 543 pLc->p_next = p_lb; 544 p_lc = p_lb; 545 p_lb = p_lb->p_next; 546 } 547 } 548 549 if(p_la != NULL){ 550 p_lc->p_next = p_la; 551 } 552 553 if(p_lb != NULL){ 554 p_lc->p_next = p_lb; 555 } 556 557 free(*(pLb));//释放Lb结点 558 (*pLb)->p_next = NULL;//Lb被直接置为空表了! 559 560 }
1 /******************************************************* 2 * @: Project: 单链表数据结构演示 3 * @: File: main.c 4 * @: Function: 单链表demo主程序 5 * @: History: 2013-10-01 22:36:03 6 * @: Author: Alimy 7 *******************************************************/ 8 9 /******************************************************* 10 * @: 头文件包含 11 *******************************************************/ 12 #include "link_list.h" 13 #include <stdio.h> 14 #include <conio.h> 15 #include <stdlib.h> 16 17 18 /******************************************************* 19 * @:(外部&内部)变量声明及定义 20 *******************************************************/ 21 22 /******************************************************* 23 * @: (外部&内部)函数声明及定义 24 *******************************************************/ 25 void printmenu(void); 26 27 28 /******************************************************* 29 * @: 主函数 30 *******************************************************/ 31 int main(){ 32 pLinkList LinkList_Display = NULL; 33 unsigned char keyValue = 0; 34 int idx = 0; 35 ElemType e = 0; 36 if(OK!=CreateList_L(&LinkList_Display,5)) 37 goto _end; 38 39 while(1){ 40 system("cls"); 41 printmenu(); 42 fflush(stdin); 43 scanf("%c",&keyValue); 44 fflush(stdin); 45 switch(keyValue){ 46 case 'a': 47 printf("请输入你要插入的位置索引及要插入的数据\n"); 48 scanf("%d%d",&idx,&e); 49 printf("你要插入数据的位置是 【%d】,要插入的数据是【%d】\n",idx,e); 50 InsertElem_L(&LinkList_Display,idx,e); 51 printf("按任意键返回主菜单\n"); 52 getch(); 53 break; 54 55 case 'b': 56 printf("请输入你要删除单链表中的元素的索引\n"); 57 scanf("%d",&idx); 58 printf("你要删除数据的位置是 【%d】\n",idx); 59 if(OK==DeleteElem_L(&LinkList_Display,idx,&e)){ 60 printf("删除元素成功,被删除的元素值为 %d \n",e); 61 } 62 printf("按任意键返回主菜单\n"); 63 getch(); 64 break; 65 case 'c': 66 printf("请输入你要得到单链表中的元素的索引\n"); 67 scanf("%d",&idx); 68 if(OK!=GetElem_L(&LinkList_Display,idx,&e)){ 69 printf("获取元素失败,请检查相关输入是否符合操作条件\n"); 70 } 71 else{ 72 printf("获取到的元素是 %d \n",e); 73 } 74 printf("按任意键返回主菜单\n"); 75 getch(); 76 break; 77 case 'd': 78 printf("请输入你要定位单链表中的元素值\n"); 79 scanf("%d",&e); 80 LocateElem_L(&LinkList_Display,e); 81 printf("按任意键返回主菜单\n"); 82 getch(); 83 break; 84 case 'e': 85 idx = GetLength_L(&LinkList_Display); 86 if(LinkList_Display->p_next!=NULL){ 87 printf("当前表长为【%d】 \n", idx); 88 } 89 printf("按任意键返回主菜单\n"); 90 getch(); 91 break; 92 case 'f': 93 ClearList_L(&LinkList_Display); 94 printf("清除单链表完成,按任意键返回主菜单\n"); 95 getch(); 96 break; 97 case 'g': 98 DisplayList_L(&LinkList_Display); 99 printf("按任意键返回主菜单\n"); 100 getch(); 101 break; 102 case 'h': 103 goto _end; 104 break; 105 default: 106 printf("你的输入环节有误,清重新输入 \n"); 107 printf("按任意键返回主菜单\n"); 108 getch(); 109 break; 110 } 111 } 112 113 114 115 _end: 116 ClearList_L(&LinkList_Display); // 释放堆空间 117 if(LinkList_Display!=NULL) 118 free(LinkList_Display); //释放头结点 119 /* 120 121 错误代码 : 122 while(LinkList_Display!=NULL) 123 free(LinkList_Display); 124 125 //刚刚才知道 free(p)之后p还是原来的数,不会变成NULL 126 研究了一下 p自身虽然是指针,但不能通过指针的值并不能改变自身的值,所以说传地址能改变原元素的值是有条件的 127 再者,传值就一定改变不了原元素的 值么 128 129 //另外一个测试代码,VC6下测试结果符合预期,其他编译器未经测试 130 // test -- start 131 #include <stdio.h> 132 void changedata(long int pointer){ 133 *((int *)pointer) = 100; 134 return ; 135 136 } 137 int main(void){ 138 int temp = 1000; 139 long int p = (long int)(&temp); // 在VC6中long int为四个字长,等于指针长度 140 printf("temp = %d \n",temp); 141 changedata(p); 142 printf("temp = %d \n",temp); 143 return 1; 144 } 145 // test--end 146 传值还是传址不能被形式表象所迷惑。 147 */ 148 getch(); 149 return 0; 150 151 } 152 153 154 /* 155 *@: 打印演示主菜单 156 *@:返回值(无) 157 */ 158 void printmenu(void){ 159 printf(" 【主菜单】: 请输入数据相应对应的操作\n"); 160 printf("【a】: 在单链表中插入元素\n"); 161 printf("【b】: 在单链表中删除元素\n"); 162 printf("【c】: 在单链表中得到元素\n"); 163 printf("【d】: 在单链表中定位元素\n"); 164 printf("【e】: 获取当前单链表的表长\n"); 165 printf("【f】: 清除单链表,整表删除\n"); 166 printf("【g】: 打印当前单链表的所有数据\n"); 167 printf("【h】: 退出当前程序\n"); 168 printf(" 您需要执行的操作项是: "); 169 } 170 171 172 173 /* 174 175 单链表结构与顺序表存储结构的比较 176 1:存储分配方式 177 顺序表:申请连续块空间 178 单链表:链式申请,存储单元任意 179 2:时间性能 180 查找: 181 顺序表:O(1) 182 单链表:O(n) 183 删除&插入: 184 顺序表:O(n) 185 单链表:第一次为O(n),后续为O(1) 186 3:空间性能 187 顺序表: 188 需要预分配,分配大了造成浪费;分配小了,容易造成溢出 189 单链表: 190 只要 有,随时可以用 191 192 193 若线性表需要频繁的查找,很少进行插入&删除操作,宜采用顺序存储结构 194 反之可以采用链式存储结构 195 196 197 例子: 198 游戏开发中,对于用户注册注册的个人信息,只读取居多,宜采用顺序存储结构 199 游戏中的武器或者装备列表,增加删除操作更多,宜采用链式存储结构 200 201 202 当线性表中的元素个数变化大或者对应用不了解的情况下,最好采用单链表结构,不必考虑存储空间的大小问题。 203 若评估知道规模大致长度,可以用顺序表。。 204 205 总之:综合各种条件考虑! 206 */
(老实说,我对单链表的头结点有点好奇,
我的想法是为头结点单独管理,然后让头结点的数据域来管理单链表的长度。。。这样在插入&删除等操作中,直接就可以用头结点的数据域来判断是否能完成插入&删除等操作了。。
1 typedef struct LHead{ //头结点,其实和 LNode的内存结构相似, 2 int LinkListLength; //数据域,可以存储当前线性表的长度,也可以什么也不存储 3 struct LNode *p_FirstNode; //指针域指向线性表的第一个元素 4 }LHead, *pLHead;
)
额。静态链表&(循环链表&双向链表)就直接跳过了,不写demo了。。
静态链表不是在拥有指针机制的其他高级语言使用链表的机制。
循环链表&双向链表和单链表的实现类似。
~不再更新,都不让我写公式,博客园太拉胯了