【转】基础知识系列2--线性表之链表
原文地址:http://www.cnblogs.com/mcgrady/p/3209419.html
上一篇我们总结完了顺序表,这一篇我们要总结的是线性表的链表,我想从以下几点进行总结。
1,为什么要使用链表?
2,链表的存储结构?
3,链表的常用操作代码实现?
1.为什么要使用链表
通过上一篇的学习,我们知道顺序表存在一些问题,主要有以下两个方面。
1,顺序表的长度是固定的,如果超出分配的长度就会造成溢出,如果存放的数据太少则会造成空间浪费。
2,在插入元素和删除元素时(尤其不在尾部时),会移动大量的元素,造成性能和效率低下。
基于以上问题,使用链表可以很好地避免顺序表中出现的问题。这也是我们要使用链表的原因。
2.链表的存储结构
从上图可以看出,单链表中的每个结点都包含一个“数据域”和一个“指针域”。“数据域”中包含当前结点的数据,“指针域”包含下一节点的存储地址,头指针head是指向开始结点的,结束结点没有后继结点,所以结束结点的指针域为空,即null。
3.链表的常用操作及实现代码
链表常用的操作有:
1,插入结点到表头
思路:将head头指针的next指针给新增结点的next,然后将整个新增结点给head头指针的next。因此时间复杂度为O(1)。
示意图:
思路:插入方法与插入到表头一样,只不过多一个步骤就是通过head头指针循环找到终端结点。因此时间复杂度为O(n)。
示意图:
思路:插入方法与插入到表头一样,多循环查找当前结点的动作。因此时间复杂度为O(n)。
示意图:
思路:同插入结点一样,时间复杂度为O(n)。
示意图:
思路:与插入结点和删除结点方法类似,时间复杂度为O(n)。
6,获取链表长度
思路:不像顺序表是连续存储的,获取表的长度非常容易。在链表中,数据不是连续存储的,因此需要循环遍历才能求得链表的长度,所以时间复杂度为O(n)。
代码实现:
1 #include <stdio.h> 2 #include <stdlib.h> 3 4 #define OK 0 5 #define ERROR -1 6 7 typedef int Status; //函数结果状态 8 typedef int ElemType; 9 typedef struct Node 10 { 11 ElemType data; 12 struct Node *next; 13 }Node; 14 typedef struct Node *ChainList; 15 Node *p; 16 ChainList head; 17 18 Status Init(ChainList *head) 19 { 20 *head = (ChainList)malloc(sizeof(Node)); 21 22 if(*head == NULL) 23 return ERROR; 24 25 (*head)->next = NULL; 26 27 return OK; 28 } 29 //由于第i个结点的存储地址是存储在第i-1个结点的next中,因此,先让指针指向第i-1个结点,然后生成一个新结点插入 30 Status Insert(ChainList head,int i,ElemType e) 31 { 32 int j=0; 33 ChainList p,s; 34 35 p = head; 36 while(p!=NULL&&j<i-1) //head内不保存数据 37 { 38 p = p->next; 39 j++; 40 } 41 42 if(p==NULL||j>i-1) //这个j>i-1代表着i不能输入小于1的非法值 43 return ERROR; 44 45 s = (ChainList)malloc(sizeof(Node)); 46 s->data = e; 47 s->next = p->next; 48 p->next = s; 49 50 return OK; 51 } 52 53 Status Delete(ChainList head,int i) 54 { 55 int j=0; 56 ElemType e; 57 ChainList p,s; 58 p=head; 59 60 while(p!=NULL&&j<i-1) 61 { 62 p = p->next; 63 j++; 64 } 65 66 if(p==NULL) 67 return ERROR; 68 else 69 { 70 s=p->next; 71 p->next = s->next; 72 e = s->data; 73 free(s); 74 return OK; 75 } 76 } 77 78 int GetLength(ChainList head) 79 { 80 int i=0; 81 ChainList p = head->next; 82 83 while(p!=NULL) 84 { 85 p = p->next; 86 i++; 87 } 88 89 return i; 90 } 91 92 Status GetDataByIndex(ChainList head,int i,ElemType *e) 93 { 94 int j=0; 95 ChainList p,s; 96 97 p=head->next; 98 99 while(p!=NULL&&j<i-1) 100 { 101 p=p->next; 102 j++; 103 } 104 105 if(p==NULL||j>i-1) 106 return ERROR; 107 *e = p->data; 108 109 return OK; 110 } 111 112 Status Display(ChainList head) 113 { 114 ChainList p=head->next; 115 printf("链表:"); 116 while(p!=NULL) 117 { 118 printf("%d ",p->data); 119 p=p->next; 120 } 121 printf("\n"); 122 123 return OK; 124 } 125 126 int main(void) 127 { 128 ChainList head; 129 ElemType e; 130 int j,k; 131 132 printf("初始化\n"); 133 if(Init(&head) == -1) 134 printf("Init Error\n"); 135 printf("初始化后,链表长度:%d\n",GetLength(head)); 136 137 printf("插入10条数据\n"); 138 srand((unsigned)time(NULL)); 139 for(j=0;j<10;j++) 140 { 141 if(Insert(head,1,j) == -1) 142 printf("Insert Error\n"); 143 } 144 Display(head); 145 146 printf("删除第3条数据\n"); 147 if(Delete(head,3) == -1) 148 printf("Delete Error\n"); 149 printf("删除成功\n"); 150 Display(head); 151 152 printf("获取第5个结点的数据\n"); 153 if(GetDataByIndex(head,5,&e) == -1) 154 printf("GetData Error\n"); 155 printf("%d\n",e); 156 157 return 0; 158 }
运行结果