链表基本类型,基本操作及例题
- 创建链表
typedef struct ListNode(){
int data;
struct ListNode* next;
}Linklist;
不带头结点:
head=NULL;
- 带头节点:
- (注意以下操作都是带头结点哟)
//定义头指针,指针域置空
struct ListNode* head=malloc(sizeof(strcut ListNode));
head->next=NULL;
- 尾插法
void tail_add(Linklist *head,int n){
Linklist *p=malloc(sizeof(struct ListNode);
p->data=n;
Linklist* t=head;
t=t->next;
while(t){
t=t->next; //找到最后一个节点
}
t->next=p;
p->next=NULL; //指针域置空
}
- 头插法
void head_add(Linklist *head,int n){
Linklist *p=malloc(sizeof(struct ListNode);
p->data=n;
p->next=head->next;
head->next=p;
}
- 增
void add(Linklist *head,int n){
Linklist *p=malloc(sizeof(struct ListNode);
Linklist *find=head;
find=head->next;
n=n-1;
while(n--){ //n为增加的节点位置
find=find->next;
}
int number;
printf("你要增加的数");
scanf("%d",&number);
p->data=number; //原理类似头插法
p->next=find->next;
find->next=p;
}
删,改,查都是类似原理,找到位置,进行改变或输出,以下是伪代码
- 删
t=head;
while(n--){
t=t->next
}
t->next=t->next->next; //指针域指向下一节点的指针域
应用如删除链表中的节点
(题目已给出节点位置,通过值和指针域的覆盖实现交换)
分享力扣删除题:
删除链表的倒数第N个结点
可以用快慢指针,也可以让指针走(总长-n) 步,替换指针域
//快慢指针
struct ListNode* removeNthFromEnd(struct ListNode* head, int n){
struct ListNode* dummy=malloc(sizeof(struct ListNode));
dummy->next=head;
struct ListNode *fast=head,*slow=dummy;
while(n--&&fast){
fast=fast->next;
}
while(fast){
slow=slow->next;
fast=fast->next;
}
slow->next=slow->next->next;
return dummy->next;
}
//总长-n
struct ListNode* removeNthFromEnd(struct ListNode* head, int n){
struct ListNode*dummy=malloc(sizeof(struct ListNode));
dummy->next=head;
struct ListNode* t=head;
int count=0;
while(t){
t=t->next;
count++;
}
struct ListNode* start=dummy;
int i=count-n;
while(i--){
start=start->next;
}
start->next=start->next->next;
return dummy->next;
}
删除链表中重复元素
(可能会删除头结点,所以设置哑节点,用x保存相同值,往后若有相同直接删除,返回dummy->next)
- 改:
t->data=n;
- 查
printf("%d",t->val);
循环链表
好处:从表中任一结点出发,均可找到表中其他结点
注意:涉及遍历操作时,由于循环链表中无NULL指针,通过判断是否等于头指针来结束遍历
- 声明类型
typedef strcut Node{
int num;
sttruct Node* next;
}*Linklist
- 建立:
Linklist create()
{
Linklist head;
LNode *p1,*p2;
char a;
head=NULL;
a=getchar();
while(a!='\n'){
p1=malloc(sizeof(struct Node));
p1->num=a;
if(head==NULL){
head=p1;
}
else{
p2->next=p1;
}
p2=p1;
a=getchar();
}
p2->next=head;
return head;
}
//主函数
void main(){
Linklist L1,head;
L1=create();
head=L1;
printf("%d",L1->num);
L1=L1->next;
while(L1!=head){
printf("%c",L->num);
L=L->next;
}
getch();
}
- 合并两个带尾指针Ta,Tb的循环链表
p=Ta->next; //p保存表头节点
Ta->next=Tb->next->next;
free(Tb->next);
Tb->next=p;
return Tb;
应用:
环形链表
(判断是否为环形链表 即快指针fast是否会遇上慢指针slow)
双向链表
好处:找前驱节点更加方便
- 建立
typedef struct ListNode{
int data;
struct ListNode*prior,*next;//定义前驱和后继节点
}Linklist
双向链表的对称性:
p->prior->next=p=p->next->prior;
- 插入
struct ListNode* s=malloc(sizeof(struct ListNode));
s->prior=p->prior;
p->prior->next=s;
s->next=p;
p->prior=s;
- 删除(需要同时改变前驱和后继的指针域)
p->prior->next=p->next;
p->next->prior=p->prior;
哑节点的应用
应用于头指针可能发生变化,如排序时的调换位置,可能删除删除头结点等,这里给出插入排序,归并排序,冒泡排序,即相关例题
- 插入排序:
给 small large 分配空间,并分别设置两头结点smallhead,largehead指向这两个链表,
struct ListNode* insertionSortList(struct ListNode* head){
struct ListNode *dummy=malloc(sizeof(struct ListNode));
dummy->next=head;
struct ListNode* lastnode=head,*cur=head->next;
while(cur){
if(lastnode->val<=cur->val){
lastnode=lastnode->next;
}
else{
struct ListNode* prev=dummy;
while(prev!=cur){
while(prev&&prev->next&&prev->next->val<=cur->val){
prev=prev->next;
}
lastnode->next=cur->next;
cur->next=prev->next;
prev->next=cur;
}
cur=lastnode->next;
}
}
return dummy->next;
}
哑节点属于重新定义类型
另外的,也有重新设置新链表,题如
分隔链表
(设两个链表,分别存放大和小,再置空 相连起来)
奇偶链表
struct ListNode* odd=head;
struct ListNode* evenhead=head->next;
struct ListNode* even=evenhead;
通过改变奇偶节点指针域 且有evenhead偶数链表开端
odd->next=even->next;
odd=odd->next;
even->next=odd->next;
even=even->next;
- 冒泡排序
ListNode *slow=head;
ListNode *fast=head->next;
while(fast){
if(slow->val>fast->val){ //升序
int temp=slow->val;
slow->val=fast->val;
fast->val=temp;
}
fast=fast->next;
slow=slow->next;
}
- 归并排序
排序链表
//治
struct ListNode* merge(struct ListNode* head1, struct ListNode* head2) {
struct ListNode* dummy=malloc(sizeof(struct ListNode));
struct ListNode* temp=dummy,*temp1=head1,*temp2=head2;
while(temp1&&temp2){
if(temp1->val>temp2->val){
temp->next=temp2;
temp2=temp2->next;
}
else{
temp->next=temp1;
temp1=temp1->next;
}
temp=temp->next;
}
if(temp2!=NULL){
temp->next=temp2;
}
if(temp1!=NULL){
temp->next=temp1;
}
return dummy->next;
}
//分
struct ListNode* sort(struct ListNode* head,struct ListNode* tail){
if(head==NULL){
return head;
}
if(head->next==tail){
head->next=NULL;
return head;
}
struct ListNode* slow=head,*fast=head;
while(fast!=tail){
slow=slow->next;
fast=fast->next;
if(fast!=tail){
fast=fast->next;
}
}
struct ListNode* mid=slow;
return merge(sort(head,mid),sort(mid,tail));
}
struct ListNode* sortList(struct ListNode* head){
return sort(head,NULL);
}
链表与递归
struct ListNode* mergeTwoLists(struct ListNode* l1, struct ListNode* l2){
if (l1==NULL){
return l2;
}
else if (l2==NULL){
return l1;
}
else if(l1->val<=l2->val){
l1->next=mergeTwoLists(l1->next,l2);
return l1;
}
else{
l2->next=mergeTwoLists(l1,l2->next);
return l2;
}
若有错误,望请指正
如果对你有帮助的话,请点个赞吧~谢谢你