一、链表的删除、查找、插入等操作
前言: 该文章内容的第一大块是单独功能的讲述,比如链表的插入,删除,查找等操作; 第二大块是整个链表的一个完整操作示例。这两个模块没有任何关联,以防误解。
1、准备内容
友情提示: 以下代码可以按序拷贝到开发工具中(有时会遇到版本兼容性问题).
该部分内容主要是准备工作,在操作之前,我们总得创建一个链表不是,接下来直接贴上。
(1)头文件
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
(2)结构体 我们链表需要存储的数据
typedef struct Node
{
char name[15]; //姓名
int age; //年龄
struct Node *next; //指向 下一个节点
}Person;
接下来我们就创建一个以Person为基础的链表,首先编写一个创建链接的函数。
(3)创建链表的函数
Person * creatList()
{
Person *head = (Person*)malloc(sizeof(Person)); //分配空间
strcpy(head->name, "TOP");
head->age = 0;
head->next = NULL ;
Person *p = head;
Person *s = NULL ;
for (int i=0; i<3; i++) {
s = (Person*)malloc(sizeof(Person));
printf("输入姓名和年龄:\n");
scanf("%s %d",s->name, &(s->age));
s->next = NULL;
p->next = s;
p = s;
}
return head;
}
紧接着我们再编写一个打印链表的函数,这样在视觉上就能直接看出来链表有没有问题,岂不是很悠哉。
(4)打印链表的函数
void show(Person *head){
Person *p = head;
while (p != NULL ) {
printf("name is %s, age is %d \n",p->name, p->age);
p = p->next;
}
printf("==================================== \n");
}
基本工作处理完了,下面我们就要真刀真枪的走一遭了。
2、操作实现
(1)创建链表 在main函数中创建一个链表head1,我们之后的操作都是基于该链表。
Person *head1 = (Person*)malloc(sizeof(Person));
head1 = creatList(); //创建链表1
show(head1); //打印链表
此时,如果代码没有符号或语句的问题,应该都能输出正确的链表。下面就讲述不同的操作功能。
(2)查找元素节点
我们用searchNode函数封装该方法,通过name来查找我们需要的节点:
Person* searchNode(Person *head, char *_name)
{
Person *p = head;
while (p != NULL) {
if (strcmp(p->name, _name) == 0) {
return p;
}
p = p->next;
}
return p;
}
之后,在main函数中调用该方法,参数“NAME”是你要查找的内容,可不能直接copy哈,比如你要查找的名字叫"Jack",就需要将参数NAME写成Jack:
Person *search = searchNode(head1, (char*)"NAME");
if (search != NULL)
{
printf("had fond ,it's that:\n");
printf("name is %s, age is %d \n",search->name, search->age);
}else{
printf("not find \n");
}
(3)查找中间元素节点
Person * centerList(Person *head)
{
Person *p = head;
int cout = 0;
while (p != NULL) {
cout ++;
p = p->next;
}
p = head;
for (int i=0; i<(cout/2); i++) {
p = p->next;
}
return p;
}
之后,我们在main函数中调用该方法,并输出:
Person *center = centerList(head1);
printf("name is %s, age is %d \n",center->name, center->age);
(4)插入元素节点到指定位置
我们用insertNode函数封装该方法,下述代码中的 strcmp(p->name, “NAME”) 中的“NAME”,就是你要指定的位置。
void insertNode(Person *head)
{
Person *p = head;
while (p != NULL) {
if (strcmp(p->name, "NAME") == 0) {
Person *s = (Person*)malloc(sizeof(Person));
printf("输入新节点信息:\n");
scanf("%s%d",s->name, &(s->age));
s->next = p->next;
p->next = s;
}
p = p->next;
}
}
之后,在main函数中调用该方法:
insertNode(head1);
show(head1); //打印一下链表,看看我们是否插入成功
(5)删除指定元素节点
我们用deleteNode函数封装该方法
Person* deleteNode(Person *head, char *_name)
{
Person *p = head;
Person *s = head->next;
if (strcmp(p->name, _name) == 0) {
head = head->next;
free(p);
p = NULL;
return head;
}
while (s != NULL) {
if (strcmp(s->name, _name) == 0) {
p->next = s->next;
free(s);
s = NULL;
return head;
}
p = s;
s = s->next;
}
return head;
}
在mian函数中直接调用, 参数NAME是你要删除的元素:
head1 = deleteNode(head1, (char*)"NAME");
show(head1); //打印一下,看看成功了没有
(6)判断链表是否有环 定义两个指针,往同一个方向移动,一个移动速度快,一个移动速度慢(比如第一个指针每次移动一个节点,第二个指针每次移动两个节点)。如果链表有环,则两个指针会在某一节点相遇。
void annularList(Person *head)
{
Person *p = head; //慢速移动
Person *s = head->next; //快速移动
while (s) {
if (s == p)
{
printf("此链表有环\n");
return;
}
else
{
s = s->next;
if (!s) {
printf("此链表没有环\n");
return;
}
else
{
s = s->next;
p = p->next;
}
}
}
}
只需要在main函数中调用一下就行:
annularList(head1)
(7) 删除整个链表
void deletaAll(Person *head)
{
Person *p = head;
Person *s = p->next;
while (s != NULL) {
free(p);
p = s;
s = s->next;
}
free(p);
p = NULL;
head = NULL;
}
在 main中调用一下就好了,参数记得传head1。
好了,第一部分单独功能的描述已经完毕了。接下来,我们再大干一场。自古讲究和为贵,我们就融合两个链表,让它们成为一家。
二、 合并成有序链表
前言: 该部分和第一大块没有关联,请不要误解。
说明: 已知两个有序链表,自定义函数把这两个链表合并成一个依然有序的链表。
注意: 以下代码,可以按序全部拷贝到开发工具中(有时会遇到版本兼容性问题)。
1、引入头文件必不可少
#include<iostream>
using namespace std;
2、我们先定义一个 NODE 结构体,包括数据 和 指向下一个节点的指针。
typedef struct Node{
int data;
struct Node *next;
}NODE;
3、准备工作结束了,我们需要先写一个创建链表的函数(在main函数中调用,样式在第5条)。
NODE* creadList(NODE *head){
NODE *p1 = NULL; //新节点指针
NODE *p2 = NULL; //动态指针
head = p2 = p1 = (NODE*)malloc(sizeof(NODE));
cout<<"请输入有序的整数,以0为结束标志:"<<endl;
cin>> p1->data;
for (; p1->data!=0; ) {
p2 = p1;
p1 = (NODE*)malloc(sizeof(NODE));
cout<<"继续输入,直到输入0结束:"<<endl;
cin>> p1->data;
p2->next = p1;
}
p2->next = NULL;
return head;
};
4、当然,创建链表之后,我们总要输出一下,看看自己创建的链表是否合法。
再编写一个打印链表的函数(在main函数中调用,样式在第5条)。
void printList(NODE *head){
NODE *p = NULL;
p = head;
if (head == NULL) {
cout<<"空表"<<endl;
}else{
cout<<"链表元素是:"<<endl;
for (;p!=NULL ; p=p->next) {
cout<<p->data<<", ";
}
cout<<endl;
}
//为了便于区分每个链表的内容,我们输出分隔符号
cout<<"==============================="<<endl;
}
5、好了,我们在main函数中调试一下,看看我们创建的链表能否正常执行。
int main(int argc, const char *argv[]){
NODE* head1 = NULL;
NODE* _head1 = creadList(head1); //创建链表1
printList(_head1);
}
可以发现,咱们的链表已经成功了,这很好。
6、接下来就是激动人心的时刻了,合并两个链表的方法 我们直接奉上。这段逻辑部分乍一看可能有些迷糊。如果你理解起来有些困难,可以拿笔在纸上写出两个有序链表,然后按照代码步骤一步一步画出来操作结果,这样就很容易理解了,其实还是很简单的。
NODE * unionList(NODE* head1, NODE* head2){
if (head1 == NULL){
return head2;
}else if (head2 == NULL){
return head1;
}
NODE *newHead = (NODE*)malloc(sizeof(NODE));
if(head1->data <= head2->data){
newHead = head1;
head1 = head1->next;
}else{
newHead = head2;
head2 = head2->next;
}
NODE *p = newHead;
while (head1 != NULL && head2 != NULL) {
if (head1->data <= head2->data) {
p->next = head1;
p = head1;
head1 = head1->next;
}else{
p->next = head2;
p = head2;
head2 = head2->next;
}
}
if (head1 == NULL) {
p->next = head2;
return newHead;
}else if(head2 == NULL){
p->next = head1;
return newHead;
}
return newHead;
}
7、最后,我们完善main函数。为了预防初学者迷糊,我们将全部的main函数代码贴上。执行代码之后,按照提示输入链表数据,我们就可以将两个链表合并成一个有序链表了。
int main(int argc, const char *argv[]){
NODE* head1 = NULL;
NODE* _head1 = creadList(head1); //创建链表1
printList(_head1);
NODE* head2 = NULL; //创建链表2
NODE* _head2 = creadList(head2);
printList(_head2);
NODE* _head = unionList(_head1, _head2); //合并 并 排序
printList(_head);
}