单链表及其基本操作
1 链表的概念及结构
概念:链表是一种物理存储结构上非连续、非顺序的存储结构,数据元素的逻辑顺序是通过链表中的指针链接次序实现的。
实际中链表的结构非常多样,以下情况组合起来就有8种链表结构: 1. 单向、双向 2. 带头、不带头 3. 循环、非循环。
常用的有无头单向非循环链表、带头双向循环链表。
1. 无头单向非循环链表:结构简单,一般不会单独用来存数据。实际中更多是作为其他数据结构的子结 构,如哈希桶、图的邻接表等等。另外这种结构在笔试面试中出现很多。
2. 带头双向循环链表:结构最复杂,一般用在单独存储数据。实际中使用的链表数据结构,都是带头双向 循环链表。另外这个结构虽然结构复杂,但是使用代码实现以后会发现结构会带来很多优势,实现反而 简单了,后面我们代码实现了就知道了。
下面是无头单向非循环链表的一些基本操作代码:
//NodeList.c #include"NodeList2.h" //遍历 void print(Node* head) { Node* cur = head; //声明一个新指针用来进行遍历 while (cur) { //cur为NULL时链表遍历完 printf("%d-->", cur->val); cur = cur->next; } printf("\n"); } //销毁链表 Node* NodeListDestory(Node* head) { Node* cur = head; while (cur) //每一个节点都要销毁 { Node* node = cur->next; free(cur); cur = node; } head = NULL; return head; } //头插 Node* NodeListPushFront(Node* head, DataType x) { Node* node = (Node*)malloc(sizeof(Node)); //申请节点 node->val = x; // 将数据放入节点中 node->next = head; //新节点的下一个节点置为原链表的头结点 return node; //返回新的头结点 //head=node;return head; } //尾插 Node* NodeListPushBack(Node* head,DataType x) { if (NULL == head) { head=NodeListPushFront(head, x); //如果原链表为空,插入第一个元素用头插 } else { //原链表不为空,申请新节点 Node* node = (Node*)malloc(sizeof(Node)); node->val = x; //将要插入的数据放入节点 node->next = NULL; //因为是尾插,所以插入的节点的下一个一定为空节点 Node* cur = head; //声明一个变量来进行遍历 while (cur->next != NULL) //cur的next为NULL时说明cur是最后一个节点 { cur = cur->next; } cur->next = node; //循环结束,cur遍历到链表最后一项的位置,使next指向新节点,完成尾插 } return head; } //头删 Node* NodeListPopFront(Node* head) { assert(head); if (NULL == head->next) //链表的第一个节点的next为空时说明链表只有一个节点 { free(head); head = NULL; return head; } else //链表不止一个节点时 { Node* node = head->next; //定义一个新指针指向head的next free(head); //释放head节点 return node; //返回node节点,即为将原链表的第二个节点返回,外部接收使其成为新的头结点 } } //尾删 Node* NodeListPopBack(Node* head) { assert(head); if (NULL == head->next) //链表只有一个节点 { free(head); head = NULL; } else //链表不止一个节点时 { Node* cur = head; while (NULL != cur->next->next) //节点的next的next为空,说明当前节点在倒数第二个节点 { cur = cur->next; } //循环结束则说明cur已经是倒数第二个节点,它的下一个是最后一个节点,也就是要删除的节点 free(cur->next); //释放cur的下一个节点,即删除最后一个节点 cur->next = NULL; //cur的next置为空,防止野指针 } return head; } //查找x并第一次在链表中出现的位置,没有该元素则输出提示信息 Node* NodeListFind(Node* head, DataType x) { assert(head); int count = 0; for (Node* cur = head; cur != NULL; cur = cur->next) { ++count; if (x == cur->val) { printf("%d\n", count); //记录x是链表中的第几个元素 return cur; //如果找到x第一次出现的位置,返回其所在的节点地址 } } count = 0; printf("链表中没有%d\n", x); return NULL; //如果会跳出循环,说明链表中没有x,返回NULL表示该元素不存在链表中 } //删除x第一次出现的节点 Node* NodeListRemove(Node* head, DataType x) { assert(head); if (x == head->val) { Node *node = head->next; free(head); return node; } else { Node* cur = head; while (cur) { if (x == cur->next->val) //第一个元素已经在前面判断过,所以从第二个元素的值开始判断 { //当前节点的next节点的值为x时进行删除操作 Node* node = cur->next; //记录下要删除的节点,以免断开链接后失去地址,无法释放 cur->next = cur->next->next; //当前节点的next指向next的next,完成删除 free(node); //释放删除的节点的空间 return head; } cur = cur->next; } } }
//NodeList.h typedef int DataType; typedef struct Node { DataType val; struct Node* next; }Node; //销毁链表 Node* NodeListDestory(Node* head); //头插 Node* NodeListPushFront(Node* head, DataType x); //遍历 void print(Node* head); //尾插 Node* NodeListPushBack(Node* head, DataType x); //头删 Node* NodeListPopFront(Node* head); //尾删 Node* NodeListPopBack(Node* head); ////查找x并第一次在链表中出现的位置 Node* NodeListFind(Node* head, DataType x); //删除x第一次出现的节点 Node* NodeListRemove(Node* head, DataType x); //删除值为x的所有节点 Node* NodeListRemoveAll(Node* head, DataType x);
//test.c #include"NodeList2.h" void test() { Node* head; head = NULL; //链表为空即为初始化 head = NodeListPushFront(head, 5); head = NodeListPushFront(head, 4); head = NodeListPushFront(head, 3); head = NodeListPushFront(head, 2); head = NodeListPushFront(head, 1); head = NodeListPushFront(head, 5); print(head); head = NodeListPushBack(head, 6); head = NodeListPushBack(head, 7); head = NodeListPushBack(head, 8); head = NodeListPushFront(head, 5); //head=NodeListDestory(head); print(head); //head = NodeListPopFront(head); //print(head); //head = NodeListPopFront(head); //print(head); //head = NodeListPopBack(head); //print(head); //head = NodeListPopBack(head); //print(head); //Node* pos = NodeListFind(head, 11); //head=NodeListRemove(head, 5); //print(head); system("pause"); } int main() { test(); return 0; }
住进火焰就成为萤火虫。