今天花了一天时间把单向链表的创建,增加,删除,修改,查找,遍历等问题用C++实现了一遍,把以前好多模糊的地方,终于弄清楚了。现在把这些内容记录下来。
1. 创建单向链表结点
我们通常用一个结构体表示链表结点,如下:
struct ListNode {
int data; //链表数据域
ListNode* next; //链表下一个结点
ListNode() {
data = 0;
next = NULL;
}
};
2. 插入新结点
bool InsertListNode(ListNode* head, int pos, int data) { //head为链表头结点,pos为插入的位置,即在第pos个结点后插入,data为要新插入的数据
if (NULL == head) { //判断链表是否为空
return false;
}
ListNode* p = head;
ListNode* q = (ListNode*)(<span class="KSFIND_CLASS" id="0KSFindDIV">malloc</span>(sizeof(ListNode))); //为新插入结点分配内存
q->data = data; //新插入结点数据为data
int count = 0;
if (pos >= 0) {
while (p->next != NULL) { //遍历链表找到第pos个结点
++count;
p = p->next;
if (count == pos) {
break;
}
}
q->next = p->next; //开始插入q结点,让p的后继结点称为q的后继结点
p->next = q; //让q成为p的后继结点
return true;
}
}
3.删除指定结点
bool DeleteListNode (ListNode* head, int pos) {
if (NULL == head) {
return false;
}
int count = 0;
ListNode* p = head;
if (pos > 1) {
while (p != NULL) { //找到删除结点的前一结点p
++count;
if (count == pos) {
break;
}
p = p->next;
}
ListNode* temp = p->next; //要定义一个中间变量来存储要删除的结点,这样才能释放删除结点所占内存,从而防止内存泄露
p->next = temp->next;
free(temp);
//若这样直接赋值p->next = p->next->next;会造成内存泄露
return true;
}
}
4.查找指定结点
bool FindListNode(ListNode* head, int data) {
if (NULL == head) {
return false;
}
ListNode* p = head->next;
while (p != NULL) {
if (p->data == data) {
return true;
}
p = p->next;
}
}
5.修改指定结点数据
bool ModifyListNode(ListNode* head, int data, int new_data) {
if (NULL == head) {
return false;
}
ListNode* p = head;
while (p != NULL) {
if (p->data == data) {
p->data = new_data;
return true;
}
p = p->next;
}
}
6. 循环遍历链表
void LoopListNode(ListNode* head) {
if (NULL == head) {
return;
}
ListNode* p = head;
while (p != NULL) {
std::cout << p->data;
p = p->next;
}
}
7.递归遍历链表
void RecursiveListNode(ListNode* head) {
if (NULL == head) {
return;
}
std::cout << head->data;
RecursiveListNode(head->next);
//如果将打印放在递归调用后面执行,则会实现链表的逆序打印,原因是递归是用栈保存中间变量的,利用了栈的后进先出原理
}