写这篇博文的原因
C语言有三个重要部分:流程控制、函数、指针。对于指针,单单了解它的简单运用是远远不够的,最重要的是学习链表。所以这篇文章通过用C语言实现链表的一些基本操作和总结,希望对C语言的指针有更新的理解和认识。
单链表的定义
单链表是通过一组任意的存储单元来存储线性表中的数据元素,这些存储单元可以是连续的也可以是不连续的。为了建立起数据元素之间的关系,对于每个数据元素除了存放元素自身的信息外,还必须有包含指向该元素直接后继元素位置的信息,这两部分信息组成一个节点,即每个节点都有至少包含两个域,一个域存储数据元素信息,称为数据域,另一个域存储直接后继的地址,称为指针域。
typedef struct ListNode { int data; ListNode *next; }ListNode;
当n 个元素的线性表通过每个节点的指针域连接像一条"链子",故形象称之为链表
单链表的基本操作
- 链表的初始化;
- 链表的插入;
- 链表的创建;
- 链表节点的插入;
- 链表节点的删除;
- 链表的销毁;
- 获取链表的长度;
- 链表的倒置;
- 链表的遍历;
单链表的基本操作的完整代码实现
注:下面代码实现的所有链表均是带头结点的链表,即头指针的data为空,初始化时使头指针->next = NULL,头指针->data不做处理。
网上关于链表操作的博文带头结点和不带头结点的均有,没有一个统一的标准,其实原理是一样的,每个函数方法只要稍微修改就能实现响应的功能,看个人喜好,没有差别。以下代码带VS2012编译器中编译通过。
#include <iostream> using namespace std; typedef struct ListNode { int data; ListNode *next; }ListNode; bool initList(ListNode **head); //初始化链表 void insertList(ListNode *head, int data); //尾插法插入函数 ListNode *createList(int *arr, int len); //创建链表 bool destroyList(ListNode **head); //摧毁链表 bool ListInserLocateNum(ListNode * head, int i, int data); //在带头结点的单链表的第i个位置之前插入元素 bool ListDelete(ListNode *head, int i, int *data); //删除第i个元素,并由data返回其值 int getListLength(ListNode *head); //获取链表的长度 void reverseList(ListNode *head); //链表倒置 void ListTraverse(ListNode *head); //遍历链表 //初始化链表 bool initList(ListNode **head) { *head = (ListNode *)malloc(sizeof(ListNode)); if(*head == NULL) { return false; } (*head)->next = NULL; return true; } //创建链表 ListNode *createList(int *arr, int len) { ListNode *p = NULL; bool flag = initList(&p); if(flag) { for(int i = 0; i < len; ++i) { insertList(p, arr[i]); } return p; } cout << "链表初始化失败" << endl; return NULL; } //尾插法 void insertList(ListNode *head, int data) { ListNode *node = (ListNode *)malloc(sizeof(ListNode)); node->data = data; node->next = NULL; ListNode *p = head; while(p->next != NULL) { p = p->next; } p->next = node; } //摧毁链表 bool destroyList(ListNode **head) { ListNode *p; while(*head) { p = (*head)->next; free(*head); *head = p; } return 1; } //在带头结点的单链表的第i个位置之前插入元素 bool ListInserLocateNum(ListNode * head, int i, int data) { ListNode *p = head; int j = 0; //带头结点,故从0开始 while(p != NULL && j < i-1) { j++; p = p->next; } if(p == NULL || j >= i) return false; ListNode *node = (ListNode *)malloc(sizeof(ListNode)); node->data = data; node->next = p->next; p->next = node; return true; } //删除第i个元素,并由data返回其值 bool ListDelete(ListNode *head, int i, int *data) { ListNode *p = head; int j = 0; while(p != NULL && j < i-1) { j++; p = p->next; } //该方法最多只能定位到最后一个节点 if(p->next == NULL || j > i-1) return false; ListNode *pNext = p->next; *data = pNext->data; p->next = pNext->next; free(pNext); return true; } //获取链表的长度 int getListLength(ListNode *head) { ListNode *p = head->next; int i = 0; while(p != NULL) { i++; p = p->next; } return i; } //链表倒置 void reverseList(ListNode *head) { ListNode *p = head->next; ListNode *pReverse = NULL; while(p != NULL) { ListNode *pNext = p->next; p->next = pReverse; pReverse = p; p = pNext; } head->next = pReverse; } //遍历链表 void ListTraverse(ListNode *head) { if(head == NULL) return; ListNode *p = head->next; while(p != NULL) { cout << p->data << ","; p = p->next; } } int main() { int arr[5] = {1, 2, 3, 4, 5}; int len = sizeof(arr) / sizeof(arr[0]); ListNode *node = createList(arr, len); ListTraverse(node); cout << endl; reverseList(node); ListTraverse(node); cout << endl; cout << "length:" << getListLength(node) << endl; int flag = ListInserLocateNum(node, 3, 6); if(flag) { ListTraverse(node); } else { cout << "第i个位置超出链表的长度"; } cout << endl; int deleteNum = 0; flag = ListDelete(node, 3, &deleteNum); if(flag) { ListTraverse(node); } else { cout << "你要删除的节点已超出链表的长度"; } cout << endl; cout<< deleteNum << endl; flag = destroyList(&node); if(flag) { cout << "链表已销毁" << endl; ListTraverse(node); } system("pause"); return 0; }