C/C++链表的基本操作(新建,输出,删除,插入,查找,逆序,排序,释放链表,链表长度计算,查找倒数第k节点的元素)

链表的一些操作(新建,输出,删除,插入,查找,逆序,排序,释放链表,链表长度计算,查找倒数第k节点的元素)

作为一个刚刚进入大学的萌新,一直都是在看别人写的博客,终于有一天可以试着写自己的博客了!

一. 链表的概念

1、链表是物理存储单元上非连续的、非顺序的存储结构,数据元素的逻辑顺序是通过链表的指针地址实现,有一系列结点(地址)组成,结点可动态的生成。

2、结点包括两个部分:
一、存储数据元素的数据域(内存空间)
二、存储指向下一个结点地址的指针域。
3、相对于线性表顺序结构,操作复杂。

二.链表的作用

1、实现数据元素的存储按一定顺序储存,允许在任意位置插入和删除结点。

2、包括单向结点,双向结点,循环接点

3、C/C++/Java都可以实现

三.链表的优缺点

优点:链表实现数据元素储存的顺序储存,是连续的

缺点:因为含有大量的指针域,所以占用空间大,同时因为只有头结点(后面说明)是明确知道地址的,所以查找链表中的元素需要从头开始寻找,非常麻烦。

四.建立一个链表结点结构

struct linked_list
{
	int num;
	linked_list *next;
};

五.对链表的操作

介于本人初学链表,只能对单链表进行一些基础操作

1.新建链表(新建一个长度为n的链表)

linked_list* create(linked_list *head,int n)
{
	linked_list *ptr,*tail=NULL;
	head=NULL;
	for(int i=0;i<n;i++)
	{
		ptr=(linked_list*)malloc(sizeof(linked_list));
		scanf("%d",&ptr->num);
		ptr->next=NULL;
		if(!head)
			head=ptr;//对首节点进行赋值
		else
			tail->next=ptr;//新增链表尾部
		tail=ptr;//尾节点移动 
	}
	return head;
}//新建一个长度为n的链表并返回首节点的地址

2.删除(释放)链表

在单链表中我们在程序的最后加上一个释放内存的方法或者操作,这是一个很好的习惯。(我对这个操作其实不是很懂,有问题请指出,以下是我对代码)

void release(linked_list *head)
{
	linked_list *ptr=head;
	while(head)
	{	
		ptr=head;
		head=head->next;
		free(ptr);
	}
	free(head); 
	if(!head)
		cout<<"链表已删除,请重新输入链表长度\n"; 
}//删除整个链表 

3.插入一个数据到链表中的某个位置

linked_list* insert(linked_list* head, linked_list* ptr, int n, int l)
{
	linked_list* h = head;
	if (n == 1)//插入到第一个位置
	{
		ptr->next = head;
		head = ptr;
	}
	else
	{
		for (int i = 0;i < n - 2;i++)
			h = h->next;
		ptr->next = h->next;
		h->next = ptr;
	}
	return head;
}//插入某个数据到n位置 ,并返回首节点

4.删除链表中的第n个位置的的节点

我用的方法是覆盖法
当需要删除一个节点p时,只需要将p的前一个节点的next赋为p->next,但是由于是单向的,只知道p,无法知道p前一个节点,所以需要转换思路。将p下一个的节点覆盖到p节点即可,这样就等效于将p删除了。(当然呢我这并没有把那个节点给释放掉,不知道会不会出问题)

linked_list* del(linked_list* head, int l, int n)
{
	linked_list* h = head;
	if (l == 1)//删除首节点
		head = head->next;
	else//删除中间节点
	{
		for (int i = 0;i < l - 2;i++)
			h = h->next;
		h->next = h->next->next;
	}
	return head;
}//删除第l个位置的节点,并返回首节点

5.对单向链表第a到第b位置的节点反转

思路是这样的:
要求将一带链表头List head的单向链表逆序。

分析:

1). 若链表为空或只有一个元素,则直接返回;

2). 设置两个前后相邻的指针p,q. 将p所指向的节点作为q指向节点的后继;

3). 重复2),直到q为空

4). 调整链表头和链表尾
Alt

linked_list* reverse(linked_list *head,int a,int b,int n)
{
	linked_list *p=head,*q=head->next,*s=NULL,*h=head;
	if(a>b)
	{
		int temp=a;
		a=b;
		b=temp;
	}
	
	int qq=b-a,t=a-2;
	if(head==NULL||head->next==NULL||a==b)//当链表为空或者链表只有一个节点或者a==b时候,直接返回head 
		return head;

	if(a==1&&b>1)//a==1时候对链表a到b进行逆序 
	{
		b--;
		while(b--)
		{
			s=q->next;
			q->next=p;
			p=q;
			q=s;
		}
		head->next=q;
		head=p;
		return head;
	}
	
	//a!=1的时候对a到b位置进行逆序 
	a--;
	
	while(a--)
	{
		p=p->next;
		q=q->next;
	}//p移动到第a个位置,q移动到a+1个位置
	while(t--)
		h=h->next;//h是p的前一个位置
	
	while(qq--)//对第a个位置到第b个位置的链表进行倒序 
	{
		s=q->next;
		q->next=p;
		p=q;
		q=s;
	}
	h->next->next=q;
	h->next=p;
	return head;
}//对链表a到b位置的数据逆序并返回head的位置; 

6.查找链表中数据为a的第一个节点的位置

int find(linked_list *head,int a,int n)
{
	int sum=1;
	while(head)
	{
		if(head->num==a)
			break;
		sum++;
		head=head->next;
	}
	if(sum>n)
		return -1;
	return sum;
}//查找数据为a的节点的位置 

7.链表排序操作

linked_list* linked_listsort(linked_list *head,int p)//p判断进行升序还是降序操作 
{
	linked_list *slow=head,*fast=NULL;
	int temp;
	if(p==1)//升序排序 
	{
		while(slow)//冒泡思想,就不解释了 
		{
			fast=slow->next;
			while(fast)
			{
				if(fast->num<slow->num)
				{
					temp=slow->num;
					slow->num=fast->num;
					fast->num=temp;
				}
				fast=fast->next;
			}
			slow=slow->next;
		} 
		cout<<"你已进行了升序排序,查看排序结果请输入1\n"; 
	}
	else//降序排序 
	{
		while(slow)
		{
			fast=slow->next;
			while(fast)
			{
				if(fast->num>slow->num)
				{
					temp=slow->num;
					slow->num=fast->num;
					fast->num=temp;
				}
				fast=fast->next;
			}
			slow=slow->next;
		} 
		cout<<"你已进行了降序排序,查看排序结果请输入1\n"; 
	}
	return head;
}

8.计算链表长度

int lengthofLinklist(linked_list *head) 
{
	int len = 0;
	while(head)
	{
		head=head->next;
		len++;
	}
	return len;
}//计算链表长度

9.查找链表倒数第k个元素

//两次遍历查找倒数第k元素
linked_list* findKthTail(linked_list *head, int k) 
{
    if (head==NULL || k<=0) return NULL; 
    int len = 0;
    linked_list *root=head;
    while (head) 
	{
        head=head->next;
        len++;
    }
    if (len<k) return NULL;
    int countdown = len-k;
    while (countdown--)
        root=root->next;
    return root;
}

//快慢指针 查找倒数第k元素
linked_list* findKthTail2(linked_list* head, int k) 
{
    if (head == NULL || k <= 0) return NULL;
    linked_list *slow = head;
    linked_list *fast = head;
    for(int i=0;i<k;i++) 
	{  //快指针先走k步
        if(fast) 
			fast = fast->next;
        else 
			return NULL;//如果k>链表长度 返回NULL; 
    }
    while(fast) //相当于slow移动了 链表长度len - k步; 
	{
        fast = fast->next;
        slow = slow->next;
    }
    return slow;
}

10.代码整合

#include<bits/stdc++.h>
using namespace std;
struct linked_list
{
	int num;
	linked_list* next;
};

linked_list* reverse(linked_list* head, int a, int b, int n)
{
	linked_list* p = head, * q = head->next, * s = NULL, * h = head;
	if (a > b)
	{
		int temp = a;
		a = b;
		b = temp;
	}

	int qq = b - a, t = a - 2;
	if (head == NULL || head->next == NULL || a == b)//当链表为空或者链表只有一个节点或者a==b时候,直接返回head 
		return head;

	if (a == 1 && b > 1)//a==1时候对链表a到b进行逆序 
	{
		b--;
		while (b--)
		{
			s = q->next;
			q->next = p;
			p = q;
			q = s;
		}
		head->next = q;
		head = p;
		return head;
	}

	//a!=1的时候对a到b位置进行逆序 
	a--;

	while (a--)
	{
		p = p->next;
		q = q->next;
	}//p移动到第a个位置,q移动到a+1个位置
	while (t--)
		h = h->next;//h是p的前一个位置

	while (qq--)//对第a个位置到第b个位置的链表进行倒序 
	{
		s = q->next;
		q->next = p;
		p = q;
		q = s;
	}
	h->next->next = q;
	h->next = p;
	return head;
}//对链表a到b位置的数据逆序并返回head的位置; 

//head是首节点,l是待删除位置,n是链表长度
//这个函数的l和n和上个插入函数的不大一样,无伤大雅吧,嘿嘿
linked_list* del(linked_list* head, int l, int n)
{
	linked_list* h = head;
	if (l == 1)//删除首节点
		head = head->next;
	else//删除中间节点
	{
		for (int i = 0;i < l - 2;i++)
			h = h->next;
		h->next = h->next->next;
	}
	return head;
}//删除第l个位置的节点,并返回首节点

//head是首节点,ptr是存放待插入数据的节点,l是链表长度,n是待插入的位置
linked_list* insert(linked_list* head, linked_list* ptr, int n, int l)
{
	linked_list* h = head;
	if (n == 1)//插入到第一个位置
	{
		ptr->next = head;
		head = ptr;
	}
	else
	{
		for (int i = 0;i < n - 2;i++)
			h = h->next;
		ptr->next = h->next;
		h->next = ptr;
	}
	return head;
}//插入某个数据到n位置 ,并返回首节点


void release(linked_list* head)
{
	linked_list* ptr = head;
	while (head)
	{
		ptr = head;
		head = head->next;
		free(ptr);
	}
	free(head);
	if (!head)
		cout << "链表已删除,请重新输入链表长度\n";
}//删除整个链表 

linked_list* create(linked_list* head, int n)
{
	linked_list* ptr, * tail = NULL;
	head = NULL;
	for (int i = 0;i < n;i++)
	{
		ptr = (linked_list*)malloc(sizeof(linked_list));
		cin >> ptr->num;
		ptr->next = NULL;
		if (!head)
			head = ptr;//对首节点进行赋值
		else
			tail->next = ptr;//新增链表尾部
		tail = ptr;//尾节点移动 
	}
	return head;
}//新建一个长度为n的链表并返回首节点的地址

int find(linked_list* head, int a, int n)
{
	int sum = 1;
	while (head)
	{
		if (head->num == a)
			break;
		sum++;
		head = head->next;
	}
	if (sum > n)
		return -1;
	return sum;
}//查找数据为a的节点的位置 

int lengthofLinklist(linked_list* head)
{
	int len = 0;
	while (head)
	{
		head = head->next;
		len++;
	}
	return len;
}//计算链表长度

linked_list* linked_listsort(linked_list* head, int p)//p判断进行升序还是降序操作 
{
	linked_list* slow = head, * fast = NULL;
	int temp;
	if (p == 1)//升序排序 
	{
		while (slow)//冒泡思想,就不解释了 
		{
			fast = slow->next;
			while (fast)
			{
				if (fast->num < slow->num)
				{
					temp = slow->num;
					slow->num = fast->num;
					fast->num = temp;
				}
				fast = fast->next;
			}
			slow = slow->next;
		}
		cout << "你已进行了升序排序,查看排序结果请输入1\n";
	}
	else//降序排序 
	{
		while (slow)
		{
			fast = slow->next;
			while (fast)
			{
				if (fast->num > slow->num)
				{
					temp = slow->num;
					slow->num = fast->num;
					fast->num = temp;
				}
				fast = fast->next;
			}
			slow = slow->next;
		}
		cout << "你已进行了降序排序,查看排序结果请输入1\n";
	}
	return head;
}

//两次遍历查找倒数第k元素
linked_list* findKthTail(linked_list* head, int k)
{
	if (head == NULL || k <= 0) return NULL;
	int len = 0;
	linked_list* root = head;
	while (head)
	{
		head = head->next;
		len++;
	}
	if (len < k) return NULL;
	int countdown = len - k;
	while (countdown--)
		root = root->next;
	return root;
}
//快慢指针 查找倒数第k元素
linked_list* findKthTail2(linked_list* head, int k)
{
	if (head == NULL || k <= 0) return NULL;
	linked_list* slow = head;
	linked_list* fast = head;
	for (int i = 0;i < k;i++)
	{  //快指针先走k步
		if (fast)
			fast = fast->next;
		else
			return NULL;//如果k>链表长度 返回NULL; 
	}
	while (fast) //相当于slow移动了 链表长度len - k步; 
	{
		fast = fast->next;
		slow = slow->next;
	}
	return slow;
}

int main()
{
	int n, q, op, a, b, p, k;
	cout << "请输入链表长度\n";
	while (cin >> n)
	{
		linked_list* head;
		head = (linked_list*)malloc(sizeof(linked_list));
		cout << "请输入" << n << "个数据存入链表\n";
		head = create(head, n);
		cout << "请输入你要进行的操作:\n";
		cout << "1.输出链表\n";
		cout << "2.删除链表第q个位置的数据\n";
		cout << "3.输入一个数据插入到第q个位置\n";
		cout << "4.对链表a到b位置的数据进行逆序\n";
		cout << "5.查找某个元素所在节点的位置\n";
		cout << "6.对链表进行排序\n";
		cout << "7.查找链表导数第k个元素\n";
		cout << "8.删除并释放链表\n";
		while (1)
		{
			linked_list* h = head;
			cin >> op;
			if (op == 1)
			{
				h = head;
				cout << "长度为" << lengthofLinklist(h) << "的链表为:\n";
				while (h)
				{
					cout << h->num << " ";
					h = h->next;
				}
				cout << endl << endl << "你还要进行什么操作?" << endl;
			}
			else if (op == 2)
			{
				cout << "请输入你要删除的位置:";
				cin >> q;
				head = del(head, q, n);
				cout << "你已删除第" << q << "位置的数据,要看输出结果请输入1\n";
				n--;//链表长度-1 
			}
			else if (op == 3)
			{
				linked_list* ptr = NULL;
				ptr = (linked_list*)malloc(sizeof(linked_list));
				cout << "请输入待插入的数据:";
				cin >> ptr->num;
				ptr->next = NULL;
				cout << "你要将" << ptr->num << "这个数据插入哪个位置?\n" << "请输入待插入的位置:";
				cin >> q;
				head = insert(head, ptr, q, n);
				cout << "要看输出结果请输入1\n";
				n++;//链表长度+1; 
			}
			else if (op == 4)
			{
				cout << "请输入a和b,对链表第a位置和第b位置的链表反转\n";
				cin >> a >> b;
				head = reverse(head, a, b, n);
				cout << "已对链表第" << a << "到第" << b << "位置的数据进行了反转\n";
				cout << "要看输出结果请输入1\n";
			}
			else if (op == 5)
			{
				cout << "请输入你要查找的元素:";
				cin >> a;
				int node = find(head, a, n);
				if (node < 0)
					cout << "链表中没有这个元素\n";
				else
					cout << a << "在第" << node << "个位置\n";
				cout << endl << "你还要进行什么操作?" << endl;
			}
			else if (op == 6)
			{
				cout << "你要进行升序(1)排序还是降序(2)排序?请输入你选择的排序方法:";
				cin >> p;
				head = linked_listsort(head, p);

			}
			else if (op == 7)
			{
				cout << "请输入你想查找链表中倒数第几个节点位置的值:";
				cin >> k;
				if (k > lengthofLinklist(head))
				{
					cout << "输入的长度不合法,此时链表长度为:" << lengthofLinklist(head);
					cout << "请重新输入7 进行此操作\n";
				}
				else
				{
					linked_list* q = findKthTail(head, k);
					cout << "链表中倒数第" << k << "个位置节点的值为:" << q->num << endl << "你还要进行什么操作?" << endl;
				}
			}
			else if (op == 8)
			{
				release(head);
				break;
			}
			else
				cout << "输入的操作不对哦!\n请重新输入\n";
		}
	}
	return 0;
}

在借鉴了好多大牛写的博客之后,写出了我第一篇博客;
希望有任何问题大家可以指出,我会改进的!!!

猜你喜欢

转载自blog.csdn.net/leowahaha/article/details/103649307
今日推荐