链表的一些操作(新建,输出,删除,插入,查找,逆序,排序,释放链表,链表长度计算,查找倒数第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;inum);
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). 调整链表头和链表尾
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->numnum)
{
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 (lennext;
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;inext;
else
return NULL;//如果k>链表长度 返回NULL;
}
while(fast) //相当于slow移动了 链表长度len - k步;
{
fast = fast->next;
slow = slow->next;
}
return slow;
}
10.代码整合
#include
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;
}
在借鉴了好多大牛写的博客之后,写出了我第一篇博客;
希望有任何问题大家可以指出,我会改进的!!!