单链表
1.单链表的定义:
typedef struct LNode{Elemtype data;struct Lnode *next; }LNode ,*LinkList;
//单链表的数据结构(手写)
#include<iostream>
#include<vector>
#include<algorithm>typedef int TypeElem;
//单链表的定义
typedef struct LNode {TypeElem data;struct LNode* next;
}LNode,*LinkList;//初始化单链表(带头结点)
boolInitLinkList_H(LinkList& L) {L = (LNode*)malloc(sizeof(LNode));//L = new LNode;等价写法c++L->next = NULL;return true;
}
//不带头结点的单链表初始化
bool InitLinkList_(LinkList&L){L = NULL;return ture;
}
/*求表长O(n),扫描链表*/
int Length(LinkList&L){int ltn=0;p = L->next;while(p){p=p->next;len++;}return len;}/*按位序查找节点*/
LNode* GetElem(LinkList L,int pos){LNode*p = L->next;int j=1;while(p&&j<=pos){j++;p = p->next;}return p;//返回第pos个节点的指针或NULL
}
/*按值查找表节点*/
LNode*LocateElem(LinkList&L,int val){LinkList p = L->next;while(p && p->data!=val)p = =->next;return p;}
/*插入节点O(n)时间主要消耗在查找到第i-1个节点上,若在指定节点后插入新节点则只需O(1)*/
bool ListInsert(LinkList&L,int pos,int e){LinkList p =L->next;int j=1;while(p && j<pos-1)p = p->next;if(!p)return false;LNode*s = (LNode*)malloc(sizeof(LNode));s->data = e;s->next =p->next;p->next = s;return true;}
/* 删除节点*/
bool ListDelete(LinkList&L,int pos,int &e){LinkList p = L->next;while(p&&j<pos-1){p = p->next;j++;}if(!p)return false;//链表为空LNode*q =p->next;e = q->data;//用e返回被删除的元素的值p->next = q->next;free(q);return true;}
2.单链表的插入与删除
2-1按位序插入(在某一节点的后面插入新节点)
//带头结点 bool ListInsert(LinkList &L,int i,Elemtype e){if(i<1)return false;LNode*p;int j =0;p = L;while(p!=NULL && j<i-1){//找到第i-1个节点(节点i的前驱节点)p = p->next;j++;}if(p==NULL)//i值不合法return false;//插入操作(可封装为函数)LNode *s = (LNode *)malloc(sizeof(LNode));s->data = e;s->next = p->next;p->next = s;return true; }
3.单链表的建立(头插法/尾插法)
//迭代法
/*假设链表为 1→2→3→∅我们想要把它改成 ∅←1←2←3。
算法设计基本思想:在遍历链表时,将当前节点的 next 指针改为指向前一个节点。由于节点没有引用其前一个节点,因此必须事先存储其前一个节点。在更改引用之前,还需要存储后一个节点。最后返回新的头引用
时空复杂度分析:时间复杂度O(n),只需扫描一遍链表空间复杂度O(1),原地逆置
*/
ListNode* reverseList(ListNode* head) {ListNode*pre = nullptr;//节点的前一个结点ListNode*cur = head;while(cur){ListNode*ne = cur->next;//存储当前结点的后继节点cur->next = pre;//将当前节点的后继节点改为其前驱节点pre = cur;cur = ne;//迭代更新当前节点}return pre;}//递归法逆置ListNode* reverseList(ListNode* head) {if (!head || !head->next) {return head;}ListNode* newHead = reverseList(head->next);head->next->next = head;head->next = nullptr;return newHead;}
/*在带头结点的单链表L中删除所有值为x的节点,并释放其空间*/
void DeleteX(LinkList&L,int x){LNode*p = L;while(p->next){if(p->next-val==x){LNode*q = p->next;p->next = q->next;qfree(q);}else{p=p->next;}}
}
int DeleteMinEle(LinkList& L,int e) {if (L->next == NULL) {// List is emptyreturn -1; // or any other appropriate value}LNode* min_pre = L;LNode* min_node = L->next;LNode* p = L->next->next; // Start from the second nodeLNode* pre = L->next;while (p) {if (p->data < min_node->data) {min_pre = pre;min_node = p;}pre = p;p = p->next;}e= min_node->data;min_pre->next = min_node->next;free(min_node);return e;//返回最小元素
}
/*就地逆置带头结点的单链表*/
void ReverseLinkList_H(LinkList& L) {if (L->next == NULL|| L->next->next==NULL)return;//链表为空或只有一个数据节点,无需逆置LNode* p = L->next;LNode* pre = NULL;while (p != NULL) {LNode* ne = p->next;p->next = pre;pre = p;p = ne;}L ->next=pre;//切记逆置后要更新头节点!!!return;
}
设 C = a 1 , b 1 , a 2 , b 2 , ⋅ ⋅ ⋅ , a n , b n C={a_1,b_1,a_2,b_2,···,a_n,b_n} C=a1,b1,a2,b2,⋅⋅⋅,an,bn为线性表,才用带头结点的单链表存放,设计一个就地工作算法,将其拆分为两个线性表 A = a 1 , a 2 , ⋅ ⋅ ⋅ , a n , B = b 1 , b 2 , ⋅ ⋅ ⋅ , b n A={a_1,a_2,···,a_n},B={b_1,b_2,···,b_n} A=a1,a2,⋅⋅⋅,an,B=b1,b2,⋅⋅⋅,bn
void breakLinkList(LinkList&L){//先获取单链表的长度int len = Length(L);LNode*curr=L->next;//L->next=NULL;//摘取原链表的头节点LinkList A= new LNode;LinkList B = new LNode;A->next=NULL,B->next=NULL;LNode* s1=A,*s2=B;for(int i=1;i<=len;i++){LNode*ne = p->next;if(i&1){p->next=NULL;s1->next =p;s1 = p;}else{p->next=NULL;s2->next =p;s2 = p;}p = ne;}printList(A);printList(B);}
对一个有序单链表去重处理O(n)
//对一个有序单链表去重处理O(n)
void DeleteMulEle(LinkList& L) {if (L == NULL || L->next == NULL) // If the list is empty or has only one node, no duplicates to removereturn;LNode* p = L->next;LNode* pre = L;while (p!=NULL&&p->next!=NULL) {if (p->data != p->next->data) {pre = p;}else {LNode* q = p->next;p->next = q->next;free(q);}p = p->next;}}
已知两个单链表A和B分别表示两个集合,其元素递增有序,编写函数求A与B的交集,并存放于A链表中。
void MergePublicElem(LinkList& A, LinkList& B) {/*算法设计基本思想:由于链表元素单调有序,故采用归并的思想提取公共元素。时间复杂度:O(lenA+lenB);空间复杂度:O(1);*/LNode* pa = A->next;LNode* pb = B->next;LNode* La = A->next;LNode* pre = A;while (pa != nullptr && pb != nullptr) {if (pa->data == pb->data) {La->data = pa->data;pre = La;La = La->next;pa = pa->next;pb = pb->next;}else if (pa->data < pb->data) {pa = pa->next;}else {pb = pb->next;}}pre->next=NULL;delete La;printList(A);return;
}
两个整数序列A和B已经存放到两个单链表中,请设计算法,判断B序列是否是A序列的连续子序列。
bool AIsSubseqB(LinkList&A,LinkList &B){
/*算法设计基本思想:本题采用朴素匹配算法实现时间复杂度:O(nm);空间复杂度:O(1);
*/LNode*pa= A->next;LNode*pb = B->next;LNode*pre = A;while(pa&&pb){if(pa->data== pb->data){pa = pa->next;pb = pb->next;}else{//如果值不相等pre = pre->next;pa = pre;//A链表新的开始比较的节点pb = B->next;//pb重新指向B链表首节点} }if(!pb) return true;return false;
}
判断一个带头结点的循环双链表是否对称
#include<iostream>typedef int ElemType;
//双链表的定义
typedef struct Node{ElemType data;Node* pre;Node* next;
}DNode, * DLinkList;//初始化带头结点的循环双链表
bool InitDlist_H(DLinkList& L) {L = new DNode;L->pre = L;L->next = L;return true;
}
bool InsertElems(DLinkList& L, ElemType x) {DNode* s = new DNode;s->data = x;s->next = L->next;L->next->pre = s;s->pre = L;L->next= s;//L->pre = s;return true;
}
//头插法
void Print(DLinkList L) {auto p = L->next;while (p != L) {std::cout << p->data << "->";p = p->next;}std::cout << '\n';
}
bool issymmetry(DLinkList L) {/*Algorithm design:Scan from both ends of the list towards the middle, comparing corresponding elements.Time complexity: O(n)Space complexity: O(1)*/DNode *left = L->next; // Points to the first nodeDNode *right = L->pre; // Points to the last nodewhile (left != right && right->next != left) {if (left->data != right->data)return false;left = left->next;right = right->pre;}return true;
}int main()
{DLinkList L;InitDlist_H(L);for (int i = 1; i <= 9; i++)InsertElems(L, i);Print(L);printf("%d\n",issymmetry(L));return 0;
}