C 实现链表
2019-07-27 本文已影响2人
Void_Caller
前言
第一次学数据结构,代码写的可能不是很好,大神勿喷,指出来就行。
链表
顾名思义,链表就是每个数据之间有某种连接关系的一张表。
注意:在学习链表之前首先要搞清地址(指针)的概念。
原理
我们知道,数组是一串连续的内存空间,里面存放着我们的数据。
但是链表却不同,他是一堆数据被存放到不连续的内存空间,但每组数据都会有一个变量指向下一组数据的地址(指针),以此来连接起来。
所以我们很容易就想到用C语言的结构体来储存数据和指向下一个节点的地址,最后个节点由于后面没有别的节点了,所以就指向空(NULL)了。
struct Node // 链表结构
{
int data;
struct Node *pNext;
};
操作
无非也就是增删查改之类的,具体实现里的代码注释已经写的很详细了,直接看就可以了。
具体实现(第一次写这种,可能写的不是很好,大神勿喷)
#include <stdio.h>
#include <stdlib.h>
struct Node // 链表结构
{
int data;
struct Node *pNext;
};
struct LinkedList // 记录链表的初始节点和末节点
{
struct Node *pLast; // 末节点
struct Node *root; // 初始节点
};
// Operations
// 添加节点
struct Node *addNode(struct LinkedList *list, int data)
{
struct Node *m = (struct Node*) malloc(sizeof(struct Node)); // 创建节点
m -> data = data; // 塞入数据
m -> pNext = NULL; // 把该节点的下一个节点的指针指向空
if (list -> pLast != NULL) (list -> pLast) -> pNext = m; // 如果有上一个元素,那就把上一元素的下一节点指针指向本节点
else list -> root = m; // 没有的话就充当根节点
list -> pLast = m; // 不管怎么说,把链表的当前节点设为m
return m;
}
struct Node *addNode(struct LinkedList *list, int data,int index)
{
struct Node *last = list -> pLast; // 先记录原来的最后一位
list -> pLast = list -> root; // 把记录最后一位指针的变量赋为第一个,以便遍历
struct Node *m = 0x0;
if (index != 0) {
for (int i = 1;i < index;i ++)
{
if ((list -> pLast) -> pNext == NULL) break; // 到尾巴了就跳掉
list -> pLast = (list -> pLast) -> pNext; // 把pLast一位一位往后移
}
// 准备添加元素
struct Node *next = (list -> pLast) -> pNext; // 先记录原来这个元素的后一个元素地址
m = addNode(list, data); // 添加元素(会自动和前一个元素链接起来的),但同时和原来的后面一个元素的链也断了
(list -> pLast) -> pNext = next; // 把后面的那个链接回来
} else {
list -> pLast = NULL; // 让addNode方法误以为前面没有元素了
struct Node *newRoot = addNode(list, data); // 添加元素,此时是全新的一个根节点
newRoot -> pNext = list -> root; // 和原来的根节点连回来
list -> root = newRoot; // 重新赋值根节点
m = list -> root; // 返回新添加的节点
}
if (last -> pNext != NULL) list -> pLast = last -> pNext; // 如果在末尾有添加了一个节点,那就指向x那个新的节点
else list -> pLast = last; // 恢复原来的节点
return m;
}
void removeNode(struct LinkedList *list, int index)
{
struct Node *last = 0x0; // 上一个节点,0x0,也就是NULL,是空节点
struct Node *now = list -> root; // 当前轮到的节点,一开始为root节点
for (int i = 1;i <= index;i ++)
{
if (now -> pNext != NULL) { // 如果还有下一个节点的话
last = now; // 往下轮,上一个节点就是now节点
now = now -> pNext; // 往下轮
}
else break; // 到尾巴了就退出
}
if (last == NULL) // 如果要删除root元素
{
if ((list -> root) -> pNext != NULL) // 如果root元素后面还有
{
list -> root = (list -> root) -> pNext; // 链上
} else {
list -> root = NULL; // 没有的话就把root元素也弄空
}
} else {
last -> pNext = NULL; // 断开上一个的链接
if (now -> pNext != NULL) // 如果后面还有元素的话
{
last -> pNext = now -> pNext; // 链上
}
}
free(now); // 释放删除掉的元素的内存
}
int main(int argc, const char * argv[]) {
// insert code here...
struct LinkedList list = {NULL, NULL};
addNode(&list, 2); // 增
addNode(&list, 1);
addNode(&list, 5);
addNode(&list, 4, 1); // 指定位置增
addNode(&list, 3);
removeNode(&list, 0); // 删
printf("orgin: 4 1 5 3\n");
// 查
printf("查询:\n");
int in = 0;
scanf("%d",&in);
struct Node *pSearch = list.root;
int hasFound = 1;
for (int i = 0;i < in;i ++)
{
if (pSearch -> pNext != NULL)
{
pSearch = pSearch -> pNext;
} else hasFound = 0;
}
if (hasFound) printf("%d\n",pSearch -> data);
else printf("NF!\n");
// 改
printf("修改:\nindex:\n");
scanf("%d",&in);
int to;
printf("to:\n");
scanf("%d",&to);
pSearch = list.root;
hasFound = 1;
for (int i = 0;i < in;i ++)
{
if (pSearch -> pNext != NULL)
{
pSearch = pSearch -> pNext;
} else hasFound = 0;
}
if (hasFound) pSearch -> data = to;
// 遍历
printf("开始遍历:\n");
struct Node *pNow = list.root;
struct Node *pNext;
int isf = 1;
while (pNow != NULL)
{
if (isf) isf = 0;
else printf(" ");
printf("%d",pNow -> data);
if (pNow -> pNext != NULL) {
pNext = pNow -> pNext;
free(pNow);
pNow = pNext;
} else {
free(pNow);
break;
}
}
printf("\n");
return 0;
}