数据结构与算法——单链表的实现及原理
1. 单链表的原理
链表是线性表的链式存储方式,逻辑上相邻的数据在计算机内的存储位置不必须相邻,那么怎么表示逻辑上的相邻关系呢?可以给每个元素附加一个指针域,指向下一个元素的存储位置。如图所示:
从图中可以看出,每个结点包含两个域:数据域和指针域,指针域存储下一个结点的地址,因此指针指向的类型也是结点类型链表的核心要素:? 每个节点由数据域和指针域组成 ? 指针域指向下一个节点的内存地址。
1.1 结构体定义
1 Typedef struct LinkNode 2 { 3 ElemType data; //节点中存放数据的类型 4 struct LinkNode* next; //节点中存放下一节点的指针 5 }LinkList, LinkNode;
2. 单链表初始化
链表的节点均单向指向下一个节点,形成一条单向访问的数据链
1 //单链表的初始化 2 typedef struct _LinkNode 3 { 4 int data; //结点的数据域 5 struct _LinkNode* next; //结点的指针域 6 }LinkNode, LinkList; //链表节点、链表 7 8 bool InitList(LinkList*& L) //构造一个空的单链表 L 9 { 10 L = new LinkNode; //生成新结点作为头结点,用头指针 L 指向头结点 11 if(!L)return false; //生成结点失败 12 L->next=NULL; //头结点的指针域置空 13 return true; 14 }
3. 单链表增加元素 - 单链表前插法
插入节点的要素就是要找到要插入位置的前一个节点,将这个节点的Next赋值给新节点,然后将新节点的地址赋值给前一个节点的Next便可,任意位置插入和前插法均是如此。
1 //前插法 2 bool ListInsert_front(LinkList * &L, LinkNode * node) //参数1 链表指针 参数2 要插入的节点元素 3 { 4 if (!L || !node) return false; //如果列表或节点为空返回 false 5 node->next = L->next; //将头节点指向节点1的地址 赋值给要插入节点的指针域,使要插入的节点先与后部相连 6 L->next = node; //将插入节点的地址赋值给头结点的指针域,使要插入节点与头结点相连 7 8 return true; 9 }
4. 单链表增加元素 - 单链表尾插法
1 //尾插法 2 bool ListInsert_back(LinkList*& L, LinkNode* node) 3 { 4 LinkNode* last = NULL; //创建空指针, 5 if (!L || !node) return false; //如果列表或节点为空返回 false 6 7 last = L; 8 while (last->next) last = last->next; //使用 last 找到最后一个节点 9 10 node->next = NULL; //要插入节点由于在尾部,指针域置为 NULL 11 last->next = node; //将要插入节点的地址赋值给之前的尾部节点的指针域,将要插入节点放置到尾部 12 return true; 13 }
5. 单链表增加元素 - 单链表任意位置插入
插入节点的要素就是要找到要插入位置的前一个节点,将这个节点的Next赋值给新节点,然后将新节点的地址赋值给前一个节点的Next便可,任意位置插入和前插法均是如此。
1 //任意位置插法 2 bool LinkInsert(LinkList*& L, int i, int& e) //参数1 链表指针 参数2 要插入的位置 参数3 要插入的节点元素 3 { 4 LinkList* p = L, * s; 5 int j = 0; 6 7 while (p && j < i - 1) //查找第i-1个结点(要插入位置的前一个节点),p指向该结点 8 { 9 p = p->next; 10 j++; 11 } 12 13 if (!p || j > i - 1) //验证数据有效性 14 { 15 return false; 16 } 17 18 s = new LinkNode; //生成新结点 19 s->data = e; //将新结点的数据域置为 e 20 s->next = p->next; //将新结点的指针域指向结点 ai,使要插入的节点先与后部相连 21 p->next = s; //将结点 p 的指针域指向要插入的结点,使要插入节点与头结点相连 22 23 return true; 24 }
6. 单链表遍历
1 void LinkPrint(LinkList*& L) //单链表的输出 2 { 3 LinkNode* p; 4 p = L->next; 5 6 while (p) //一直循环打印,直到 p->next == NULL 退出循环 7 { 8 cout << p->data << "\t"; 9 p = p->next; 10 } 11 cout << endl; 12 }
7. 单链表获取元素
1 //单链表的取值 2 //在带头结点的单链表 L 中查找第 i 个元素,用 e 记录 L 中第 i 个数据元素的值 3 bool Link_GetElem(LinkList*& L, int i, int& e) //参数1 要查找的链表指针 参数2 要查找的元素位置 参数3 要记录存放元素的值 4 { 5 int j; 6 LinkList* p; 7 p = L->next; //p指向第一个结点 8 j=1; //j为计数器 9 10 while (j < i && p) //顺链域向后扫描,直到p指向第i个元素或p为空 11 { 12 p = p->next; //p指向下一个结点 13 j++; //计数器j相应加1 14 } 15 16 if (!p || j > i) 17 { 18 return false; //i 值不合法 i>n 或 i<=0 19 } 20 21 e = p->data; //取第i个结点的数据域 22 return true; 23 }
8. 单链表查找元素
1 //按值查找 2 bool Link_FindElem(LinkList* L, int e) //在带头结点的单链表L中查找值为e的元素 3 { 4 LinkList* p; 5 p = L->next; 6 while (p && p->data != e) //顺链域向后扫描,直到p为空或p所指结点的数据域等于e 7 { 8 p = p->next; //p指向下一个结点 9 } 10 if (!p)return false; //查找失败p为NULL 11 12 return true; 13 }
9. 单链表删除
1 //单链表的节点删除 2 bool LinkDelete(LinkList*& L, int i) //在带头结点的单链表L中,删除第i个位置 3 { 4 LinkList* p = L, * q; 5 int j = 0; 6 7 while (p->next && j < i - 1) //查找第i-1个结点,p指向该结点 8 { 9 p = p->next; 10 j++; 11 } 12 13 if (!(p->next) || j > i - 1) return false; //当 i > n 或 i < 1 时,删除位置不合理 14 15 q = p->next; //临时保存被删结点的地址以备释放空间,(删除的是 P 的下一个节点) 16 p->next = q->next; //将要删除的节点的下一个节点地址覆盖要删除节点的地址(就是把要删除节点的下一个节点地址,赋值给被删除节点的前一个节点的next) 17 delete q; //释放被删除结点的空间 18 19 return true; 20 }
10. 单链表销毁
1 //单链表的销毁 2 void LinkDestroy(LinkList*& L) 3 { 4 //定义临时节点p指向头节点 5 LinkList* p = L; 6 cout << "销毁链表!" << endl; 7 8 while (p) //遍历整个链表,逐个释放直到 L->next == NULL 9 { 10 L = L->next; //L指向下一个节点 11 cout << "删除元素: " << p->data << endl; 12 delete p; //删除当前节点 13 p = L; //p 移向下一个节点 14 } 15 }
11. 完整实现
1 #include2 #include<string> 3 #include 4 5 using namespace std; 6 7 typedef struct _LinkNode 8 { 9 int data; //结点的数据域 10 struct _LinkNode* next; //结点的指针域 11 }LinkNode, LinkList; //LinkList 为指向结构体LNode 的指针类型 12 13 bool InitList(LinkList*& L) 14 { 15 L = new LinkNode; 16 if (!L) return false; //生成节点失败 17 L->next = NULL; 18 L->data = -1; 19 return true; 8979438401111 20 } 21 22 //前插法 23 bool ListInsert_front(LinkList*& L, LinkNode* node) 24 { 25 if (!L || !node) return false; 26 node->next = L->next; 27 L->next = node; 28 return true; 29 } 30 31 //尾插法 32 bool ListInsert_back(LinkList*& L, LinkNode* node) 33 { 34 LinkNode* last = NULL; 35 if (!L || !node) return false; 36 last = L; 37 while (last->next) last = last->next; 38 node->next = NULL; 39 last->next = node; 40 return true; 41 } 42 43 //指定位置插入 44 bool LinkInsert(LinkList*& L, int i, int& e) 45 { 46 if (!L) return false; 47 int j = 0; 48 LinkList* p, * s; 49 p = L; 50 while (p && j < i - 1) //查找位置为i-1 的结点,p 指向该结点 51 { 52 p = p->next; 53 j++; 54 } 55 if (!p || j > i - 1) 56 { 57 return false; 58 } 59 s = new LinkNode; //生成新节点 60 s->data = e; 61 s->next = p->next; 62 p->next = s; 63 return true; 64 } 65 66 //遍历 67 void LinkPrint(LinkList*& L) 68 { 69 LinkNode* p = NULL; 70 if (!L) { 71 cout << "链表为空." << endl; 72 return; 73 } 74 p = L->next; 75 while (p) { 76 cout << p->data << "\t"; 77 p = p->next; 78 } 79 cout << endl; 80 } 81 82 //单链表的取值 83 bool Link_GetElem(LinkList*& L, int i, int& e) 84 { 85 //在带头结点的单链表L 中查找第i 个元素 86 //用e 记录L 中第i 个数据元素的值 87 int index; 88 LinkList* p; 89 if (!L || !L->next) return false; 90 p = L->next; 91 index = 1; 92 while (p && index < i) //顺链表向后扫描,直到p 指向第i 个元素或p 为空 93 { 94 p = p->next; //p 指向下一个结点 95 index++; //计数器index 相应加1 96 } 97 if (!p || index > i) { 98 return false; //i 值不合法,i>n 或i<=0 99 } 100 e = p->data; 101 return true; 102 } 103 104 //按值查找 105 bool Link_FindElem(LinkList* L, int e, int& index) 106 { 107 //在带头结点的单链表L 中查找值为e 的元素 108 LinkList* p; 109 p = L->next; 110 index = 1; 111 if (!L || !L->next) 112 { 113 index = 0; 114 return false; 115 } 116 while (p && p->data != e) 117 { 118 p = p->next; 119 index++; 120 } 121 if (!p) 122 { 123 index = 0; 124 return false; //查无此值 125 } 126 return true; 127 } 128 129 //单链表的删除 130 bool LinkDelete(LinkList*& L, int i) 131 { 132 LinkList* p, * q; 133 int index = 0; 134 p = L; 135 if (!L || !L->next) 136 { 137 return false; 138 } 139 140 while ((p->next) && (index < i - 1)) 141 { 142 p = p->next; 143 index++; 144 } 145 146 if (!p->next || (index > i - 1)) //当 i>n 或 i<1 时,删89除7位94置38不40合1理111 147 { 148 return false; 149 } 150 q = p->next; //临时保存被删结点的地址以备释放空间 151 p->next = q->next; //改变删除结点前驱结点的指针域 152 delete q; //释放被删除结点的空间 153 return true; 154 } 155 156 //单链表的销毁 157 void LinkDestroy(LinkList*& L) 158 { 159 //定义临时节点p 指向头节点 160 LinkList* p = L; 161 cout << "销毁链表!" << endl; 162 while (p) { 163 L = L->next; //L 指向下一个节点 164 cout << "删除元素: " << p->data << endl; 165 delete p; //删除当前节点 166 p = L; //p 移向下一个节点 167 } 168 } 169 170 int main(void) 171 { 172 LinkList* L = NULL; 173 LinkNode* s = NULL; 174 175 //1. 初始化一个空的链表 176 InitList(L); 177 178 //2. 使用前插法插入数据 179 /*int n; 180 cout<<"前插法创建单链表"< 181 std::cout<<"请输入元素个数n:"; 182 cin>>n; 183 cout<<"\n 请依次输入n 个元素:" < 184 while(n>0){ 185 s = new LinkNode; //生成新节点s 186 cin>>s->data; 187 ListInsert_front(L, s); 188 n--; 189 }*/ 190 191 //3. 使用尾插法插入数据 192 /*int n; 193 cout<<"尾插法创建单链表"< 194 std::cout<<"请输入元素个数n:"; 195 cin>>n; 196 cout<<"\n 请依次输入n 个元素:" < 197 while(n>0){ 198 s = new LinkNode; //生成新节点s 199 cin>>s->data; 200 ListInsert_back(L, s); 201 n--; 202 }*/ 203 204 //4. 单链表的输出 205 /* 206 LinkPrint(L); 207 */ 208 209 //5. 任意位置插入元素 210 for (int j = 0; j < 3; j++) { 211 int i, x; 212 cout << "请输入插入的位置和元素(用空格隔开):"; 213 cin >> i; 214 cin >> x; 215 if (LinkInsert(L, i, x)) { 216 cout << "插入成功.\n\n"; 217 } 218 else { 219 cout << "插入失败!\n\n"; 220 } 221 LinkPrint(L); 222 } 223 224 //6. 单链表根据位置获取元素 225 int element = 0; 226 if (Link_GetElem(L, 2, element)) { 227 cout << "获取第二个元素成功, 值:" << element << endl; 228 } 229 else { 230 cout << "获取第二个元素失败!" << endl; 231 } 232 233 //7. 单链表根据值查询元素所在的位置 234 int index = 0; 235 if (Link_FindElem(L, 10, index)) { 236 cout << "查找元素10 存在,所在位置: " << index << endl; 237 } 238 else { 239 cout << "不存在元素10." << endl; 240 } 241 242 //8. 单链表删除元素 243 if (LinkDelete(L, 2)) { 244 cout << "删除第2 个元素成功!" << endl; 245 LinkPrint(L); 246 } 247 else { 248 cout << "删除第2 个元素失败!" << endl; 249 } 250 251 //9. 销毁单链表 252 LinkDestroy(L); 253 system("pause"); 254 return 0; 255 }
======================================================================================================================