6-C/C++實現資料結構連結串列相關操作
本文程式碼分別包括:
標頭檔案、建立連結串列等
1建立連結串列
第8題驗證是否有環的建立連結串列
2遍歷連結串列函式
3刪除連結串列結點函式
4-1倒置連結串列函式-方法一改變指標指向
4-2倒置連結串列函式-方法二改變結點位置(頭插法,斷一個接一個)
5刪除倒數第n個結點-快慢指標法
6合併兩個有序連結串列
7兩數相加
8判斷連結串列中是否有環
*9求環的入口(較難,考試可能性小)
*10求環的長度
*11約瑟夫環-不包含頭結點的環刪除指定序列結點後相連
主函式
PART 1(自己寫的):
準備程式碼
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
using namespace std;
typedef struct ListNode{
int data;
struct ListNode *next;
}ListNode;
1建立連結串列
//1建立連結串列
ListNode *CreatList(){
ListNode *H,*M,*N; //定義頭結點指標H、向下連結結點指標M、新建立結點指標N
int n,c; //n為建立連結串列結點的個數,c為結點data值
H = (ListNode *)malloc(sizeof(ListNode)); //分配一塊LinkNode型別的記憶體空間做頭結點
H->next = NULL; //頭結點指標域指向空
M = H; //M先指向頭結點
printf("please input the number of nodes:");
scanf("%d",&n);
for(int i=1; i<=n; i++)
{
N = (ListNode *)malloc(sizeof(ListNode)); //新建立子結點
printf("please input %dth data:",i);
scanf("%d",&c); //新建立結點data值
N->data = c;
M->next = N; //通過M指標將新結點連結進單連結串列
M = N; //M指向最後一個結點
}
M->next = NULL;
printf("\n");
return H;
}
第8題驗證是否有環的建立連結串列
//第8題驗證是否有環的建立連結串列
ListNode *CreatList2(){
ListNode *H,*M,*N;
int n,c;
H = (ListNode *)malloc(sizeof(ListNode));
H->next = NULL;
M = H;
printf("please input the number of nodes:");
scanf("%d",&n);
for(int i=1; i<=n; i++)
{
N = (ListNode *)malloc(sizeof(ListNode));
printf("please input %dth data:",i);
scanf("%d",&c);
N->data = c;
M->next = N;
M = N;
}
M->next = H->next->next;
printf("\n");
return H;
}
2遍歷連結串列函式
//2遍歷連結串列函式
void TraverseList(ListNode *pHead){
ListNode *p = pHead->next;
while(p != NULL)
{
printf("%d ",p->data);
p = p->next;
}
printf("\n");
}
3刪除連結串列結點函式
//3刪除連結串列結點函式
void Del_Node(ListNode *pHead,int n){
ListNode *p = pHead; //定義p指向頭結點
ListNode *q = pHead->next; //定義q總指向p的下一個結點,q指向待刪除元素
int i = 1;
while((q != NULL) && (n>=1) && (i<=n-1)) //迴圈終止條件為第n-1個元素已經是最後一個元素或者n小於1或者已經查詢到索刪位置
{
p = p->next;
q = q->next;
i++;
}
if(q == NULL)
p->next = NULL;
else{
p->next = q->next;
free(q);
}
}
4-1倒置連結串列函式-方法一改變指標指向
//4-1倒置連結串列函式-方法一改變指標指向
ListNode *ReverseList(ListNode *pHead){
ListNode *p,*q,*r; //定義三個指標依次指向頭結點後三個結點
p = pHead->next;
q = p->next;
r = q->next;
if(p == NULL || q == NULL) //如果不存在結點或者只有一個結點,則不發生交換
return NULL;
while(r != NULL) //如果最後一個結點指向NULL,則不再需要向後移動指標
{
q->next = p;
p = q;
q = r;
r = r->next;
}
q->next = p; //對最後兩個結點進行倒敘
pHead->next->next = NULL; //將第一個結點指向NULL
pHead->next = q; //用頭結點連線連結串列第最後一個結點,完成倒敘
}
4-2倒置連結串列函式-方法二改變結點位置(頭插法,斷一個接一個)
//4-2倒置連結串列函式-方法二改變結點位置(頭插法,斷一個接一個)
ListNode *ReverseList2(ListNode * pHead){
ListNode *p,*q;
p = pHead->next;
q = p->next;
while(p != NULL && q != NULL) //如果為空連結串列或者q指向空,表示無結點調整不再執行迴圈,注意此處為!=所以要用&&
{
p->next = q->next; //將q結點摘出來插在頭結點後
q->next = pHead->next;
pHead->next = q;
q = p->next; //更新指標,使得q總指向要調整的結點,而p指標一直指向最小值
}
return pHead;
}
5刪除倒數第n個結點-快慢指標法
//5刪除倒數第n個結點-快慢指標法
ListNode *Del_FromEnd(ListNode *pHead,int n){
ListNode *slow,*fast;
slow = pHead;
fast = pHead;
if(n<1) //輸入不合法返回
{
printf("wrong,can't do it!\n");
return NULL;
}
while(fast->next != NULL && n) //此處限制的無法刪除頭結點
{
fast = fast->next;
n--;
}
while(fast->next != NULL)
{
slow = slow->next;
fast = fast->next;
}
fast = slow->next; //複用fast指標指向刪除的結點用於free
slow->next = slow->next->next;
free(fast);
return pHead;
}
6合併兩個有序連結串列
//6合併兩個有序連結串列
ListNode *MergeOderList(ListNode *pHead1,ListNode *pHead2){
ListNode *nHead = NULL; //定義一個新的頭結點
ListNode *pMove = NULL; //定義一個新的遍歷指標
if(pHead1->next == NULL) return pHead2; //如果有一個連結串列為空則返回另一個連結串列頭
else if(pHead2->next == NULL) return pHead1;
if((pHead1->next->data) <= (pHead2->next->data)) //將第一個結點鏈入新連結串列的頭結點
nHead = pHead1;
else
nHead = pHead2;
pHead1 = pHead1->next; //從第一個結點開始
pHead2 = pHead2->next;
pMove = nHead;
while((pHead1 != NULL) && (pHead2 != NULL)) //迴圈對比資料域的值,用pMove指標連線
{
if((pHead1->data) <= (pHead2->data))
{
pMove->next = pHead1;
pMove = pHead1;
pHead1 = pHead1->next;
}
else
{
pMove->next = pHead2;
pMove = pHead2;
pHead2 = pHead2->next;
}
}
if(pHead1 == NULL) //最後一個結點鏈入
pMove->next = pHead2;
else if(pHead2 == NULL)
pMove->next = pHead1;
return nHead;
}
7兩數相加
//7兩數相加
ListNode *NumberAdd(ListNode *pHead1,ListNode *pHead2){
ListNode *nHead = (ListNode *)malloc(sizeof(ListNode)); //建立頭結點
nHead->next = NULL;
ListNode *pMove = nHead; //設立一個移動指標用於連結後方結點
int symbol = 0; //進位標誌
pHead1 = pHead1->next; //兩個相加連結串列從第一個結點開始
pHead2 = pHead2->next;
while((pHead1 != NULL) || (pHead2 != NULL)) //迴圈終止條件
{
int x = (pHead1 != NULL)? pHead1->data:0; //長度不一致時將先為NULL的置為0以相加時可以得到數值
int y = (pHead2 != NULL)? pHead2->data:0;
int sum = x + y + symbol;
ListNode *p = (ListNode *)malloc(sizeof(ListNode)); //建立結點
if(sum>=10)
{
p->data = sum % 10;
symbol = 1;
}
else
{
p->data = sum;
symbol = 0;
}
pMove->next = p; //使用pMove指標將每次新建立的結點p鏈進連結串列
pMove = p;
if(pHead1 != NULL) pHead1 = pHead1->next; //兩個連結串列向下遍歷
if(pHead2 != NULL) pHead2 = pHead2->next;
}
pMove->next = NULL;
if(symbol>0) //如果最後一位相加後有進位,需要單獨再建立一個結點儲存進位值
{
ListNode *p = (ListNode *)malloc(sizeof(ListNode));
p->data = symbol;
pMove->next = p;
p->next = NULL;
}
return nHead;
}
8判斷連結串列中是否有環
//8判斷連結串列中是否有環
void IfCircle(ListNode *pHead){
ListNode *slow = pHead,*fast = pHead; //設定快慢指標,慢指標每次走1步,快指標每次走2步
if(pHead->next == NULL)
printf("NO NODE!!");
while(fast != NULL && fast->next != NULL){
slow = slow->next;
fast = fast->next->next;
if(slow == fast)
{
printf("I HAVE A CIRCLE!!\n");
break;
}
}
}
*9求環的入口(較難,考試可能性小)
//*9求環的入口(較難,考試可能性小)
ListNode *CircleEntrance(ListNode *pHead){
ListNode *slow = pHead,*fast = pHead,*Len = pHead; //設定快慢指標,慢指標每次走1步,快指標每次走2步,再設定一個指標用於遍歷頭結點到入口距離
int cot = 0; //cot用來統計環入口距離頭結點距離
if(pHead->next == NULL)
printf("NO NODE!!");
while(fast != NULL && fast->next !=NULL) //注意連結串列為奇數偶數時fast移動後指向的位置
{
slow = slow->next;
fast = fast->next->next;
/*分析:設頭結點到環入口距離為a,環長為r,slow和fast相遇時slow在環中走過的距離為x。可得相遇時慢指標走過的長度為a+x,
快指標走過的距離為(a+x+r),由於fast=2倍slow,可得a=r-x,而r-x也等於slow距離環入口的長度*/
if(slow == fast)
{
printf("I HAVE A CIRCLE!\n");
while(Len != slow) //見分析,slow與fast相遇點到環入口的距離等於頭結點到環入口的距離
{
Len = Len->next;
slow = slow->next;
cot++;
}
printf("The Circle Entrance is %dth Node!\n",cot);
return Len;
}
}
if(fast == NULL || fast->next == NULL)
return NULL;
}
*10求環的長度
//*10求環的長度
int CircleLength(ListNode *pHead){
ListNode *Head;
ListNode *a = CircleEntrance(Head);
ListNode *b = a->next; //b為環入口的下一位,使用者驗證走完一圈因為下面迴圈判斷的時候不能相等,所以這裡錯一位
int cot = 1; //cot用來統計環長
if(a == NULL)
return 0;
while(b != a) //b=a時即為環長
{
b=b->next;
cot++;
}
printf("Circle Length is %d\n",cot);
return cot;
}
*11約瑟夫環-不包含頭結點的環刪除指定序列結點後相連
//*11約瑟夫環-不包含頭結點的環刪除指定序列結點後相連
void JosphCircle(ListNode *pHead,int n){
ListNode *p = pHead->next; //p指向第一個結點
ListNode *Del = NULL; //刪除結點指標
int cot=0; //cot為統計環長
while(pHead->next != NULL)
{
pHead = pHead->next;
cot++;
}
pHead->next = p; //將連結串列變成環
if(n>=cot) printf("Bad Man!!"); //刪除序列大於環長則不存在約瑟夫環
while(p->next != p)
{
for(int i=1;i<=n;i++)
p = p->next;
Del = p->next;
printf("DELE Node Number is %d\n",Del);
p->next = Del->next;
free(Del);
/*此方法不對的原因是刪除的是不是p本身而是下一個元素?
p->data = p->next->data;
Del = p->next;
p->next = Del->next;
free(Del);*/
}
}
主函式
int main()
{
ListNode *chain,*chain1,*chain2;
chain = CreatList();
//Del_Node(chain,4);
//ReverseList2(chain);
//Del_FromEnd(chain,5);
//chain1 = CreatList();
//chain2 = CreatList();
//chain = MergeOderList(chain1,chain2);
//chain = NumberAdd(chain1,chain2);
JosphCircle(chain,2);
TraverseList(chain);
//chain = CreatList2();
//IfCircle(chain);
//CircleEntrance(chain);
//CircleLength(chain);
return 0;
}
PART 2(西交無盡):
#include<stdio.h>
#include<stdlib.h>
#define null NULL
//Definition of ListNode
typedef struct list_node
{
int data ; //資料域,用於儲存資料
struct list_node *next ; //指標,可以用來訪問節點資料,也可以遍歷,指向下一個節點
}ListNode;
//尾插法建立連結串列
ListNode *CreateList(int n)
{
ListNode *head;
ListNode *p,*pre;
int i;
head=(ListNode *)malloc(sizeof(ListNode));
head->next=NULL;
pre=head;
for(i=1; i<=n; i++)
{
printf("input name of the %d data:",i);
p=(ListNode *)malloc(sizeof(ListNode));
scanf("%d",&p->data);
pre->next=p;
pre=p;
}
p->next = NULL;
//p->next=head->next->next;
return head;
}
//遍歷連結串列函式
void TraverseList(ListNode *pHead)
{
ListNode *p = pHead->next; //將頭節點的指標給予臨時節點p
while(p != NULL) //節點p不為空,迴圈
{
printf("%d ",p->data);
p = p->next;
}
printf("\n");
return ;
}
//刪除連結串列節點函式
int Del_Node(ListNode *pHead,int back)
{
int i = 0;
int data;
ListNode *_node = pHead;
ListNode *pSwap;
if ((back < 1) && (NULL == _node->next))
{
printf("刪除失敗!\n");
return 0;
}
while(i < back-1)
{
_node = _node->next;
++i;
}
pSwap = _node->next;
data = pSwap->data;
_node->next = _node->next->next;
free(pSwap);
return data;
}
//倒置連結串列3
ListNode *node2(ListNode *pHead){
pHead = pHead->next;
ListNode *p = NULL;
while(pHead){
ListNode *nx = pHead->next;
pHead->next = p;
p = pHead;
pHead = nx;
}
return p;
}
//倒置連結串列1
ListNode *node1(ListNode *pHead){
ListNode *p = NULL;
ListNode *q = NULL;
ListNode *r = NULL;
if(pHead->next == NULL){return NULL;}
if(pHead->next->next == NULL){return pHead;}
else if(pHead->next->next->next == null) {
p = pHead->next;
q = p->next;
q->next = p;
pHead->next = q;
p->next = NULL;
}
else if(pHead->next->next->next != null){
p = pHead->next;
q = p->next;
r = q->next;
p->next = null;
while(r != NULL){
q->next = p;
p = q;
q = r;
r = r->next;
}
q->next = p;
pHead->next = q;
}
return pHead;
}
//倒置連結串列3
ListNode* ReverseList(ListNode* pHead)
{
ListNode *q=pHead->next;
ListNode *p=NULL;
ListNode *r=NULL;
if(pHead->next==NULL)
return NULL;
while(q->next)
{
r=q->next;
q->next=p;
p=q;
q=r;
}
q->next=p;
pHead->next = q;
return pHead;
}
//刪除倒數第N個節點
ListNode *removeNthFromEnd(ListNode *head, int n)
{
// write your code here
ListNode *fast = head;
ListNode *low = head;
ListNode *pre = NULL;
if(head == NULL || n <= 0)
{
return NULL; //輸入的連結串列為空,或輸入的n不合法;
}
for(int i = 0; i < n-1; i ++)
{
if(fast->next)
{
fast = fast->next;
}
else
{
return NULL; //輸入的n大於連結串列的長度;
}
}
while(fast->next)
{
fast = fast->next;
pre = low; //需要儲存需要刪除的那個結點的上一個結點。
low = low->next;
}
if(low == head) //刪除的那個結點是頭結點。
{
head = head->next;
}
else
{
pre->next = pre->next->next;
}
return head;
}
//合併兩個有序連結串列
ListNode *MergeTwoOrderedLists(ListNode *pHead1, ListNode *pHead2)
{
ListNode *pTail = NULL;//指向新連結串列的最後一個結點 pTail->next去連線
ListNode *newHead = NULL;//指向合併後連結串列第一個結點
if (pHead1->next == NULL)
{
return pHead2;
}
else if(pHead2->next == NULL)
{
return pHead1;
}
else
{
//確定頭指標
if ( pHead1->next->data < pHead2->next->data)
{
newHead = pHead1;
}
else
{
newHead = pHead2;
}
pHead1 = pHead1->next;
pHead2 = pHead2->next;
pTail = newHead; //指向第一個結點
while ( pHead1 && pHead2)
{
if ( pHead1->data <= pHead2->data )
{
pTail->next = pHead1;
pHead1 = pHead1->next;
}
else
{
pTail->next = pHead2;
pHead2 = pHead2->next;
}
pTail = pTail->next;
}
if(pHead2 != NULL)
{
pTail->next = pHead2;
}
else if(pHead1 != NULL)
{
pTail->next = pHead1;
}
return newHead;
}
}
//兩數相加
ListNode *addTwoNumbers(ListNode *pHead1, ListNode *pHead2) {
ListNode *L,*curr;
L = (ListNode *)malloc(sizeof(ListNode));
L->next = NULL;
curr = L;
ListNode *p = pHead1->next, *q = pHead2->next;
int carry = 0;
while (p != null || q != null) {
int x = (p != null) ? p->data : 0;
int y = (q != null) ? q->data : 0;
int sum = carry + x + y;
carry = sum / 10;
ListNode *r = (ListNode *)malloc(sizeof(ListNode));
r->data = sum%10;
curr->next = r;
curr = curr->next;
if (p != null) p = p->next;
if (q != null) q = q->next;
}
curr->next = NULL;
if (carry > 0) {
ListNode *r = (ListNode *)malloc(sizeof(ListNode));
r->data = carry;
curr->next = r;
curr->next->next = NULL;
}
return L;
}
//檢查環
int HasCircle(ListNode * pHead)
{
ListNode * pFast = pHead; // 快指標每次前進兩步
ListNode * pSlow = pHead; // 慢指標每次前進一步
while(pFast != NULL && pFast->next != NULL)
{
pFast = pFast->next->next;
pSlow = pSlow->next;
if(pSlow == pFast) // 相遇,存在環
return 1;
}
return 0;
}
//找出環的入口
ListNode *searchEntranceNode(ListNode *pHead)
{
ListNode *pSlow=pHead;//p表示從頭結點開始每次往後走一步的指標
ListNode *pFast=pHead;//q表示從頭結點開始每次往後走兩步的指標
while(pFast !=NULL && pFast->next !=NULL)
{
pSlow=pSlow->next;
pFast=pFast->next->next;
if(pSlow == pFast){
break;//p與q相等,單連結串列有環
}
}
if(pFast==NULL || pFast->next==NULL)
return NULL;
pSlow=pHead;
while(pSlow != pFast)
{
pSlow=pSlow->next;
pFast=pFast->next;
}
return pSlow;
}
//求環長
int circleLength(ListNode *pHead)
{
ListNode *p=searchEntranceNode(pHead);//找到環的入口結點
if(p==null)
return 0;//不存在環時,返回0
ListNode *q = p->next;
int length=1;
while(p != q)
{
length++;
q=q->next;
}
return length;//返回環的長度
}
//約瑟夫環
void JosephProblem(ListNode *pHead,int m){
ListNode *p = pHead->next;
while(pHead->next != NULL) pHead = pHead->next;
pHead->next = p;
while(p->next != p){
for(int i = 0;i<m-1;i++) p=p->next;
//列印
printf("%d ",p->next->data);
ListNode *del = p->next;
p->next = del->next;
free(del);
/*
//特殊的刪除方法
p->data = p->next->data;
ListNode *del = p->next;
p->next = del->next;
free(del);
*/
}
}
int main()
{
ListNode *chain,*nchain,*nnchain,*nnnchain = NULL;
int n,back2;
chain = CreateList(5);
JosephProblem(chain,2);
return 0;
}
(感謝西交無盡學長提供以上題目練習)
相關文章
- 資料結構 - 單連結串列 C++ 實現資料結構C++
- C++資料結構連結串列的基本操作C++資料結構
- 資料結構——單連結串列的C++實現資料結構C++
- 資料結構之連結串列操作資料結構
- js實現資料結構--單連結串列JS資料結構
- 【資料結構】連結串列(單連結串列實現+詳解+原碼)資料結構
- php實現基本資料結構之連結串列PHP資料結構
- 資料結構(雙向連結串列的實現)資料結構
- 資料結構-雙向連結串列(Python實現)資料結構Python
- 資料結構之連結串列篇(單連結串列的常見操作)資料結構
- 資料結構-單連結串列、雙連結串列資料結構
- 【C++ 資料結構:連結串列】二刷LeetCode707設計連結串列C++資料結構LeetCode
- [資料結構]連結串列的實現在PHP中資料結構PHP
- [資料結構] 連結串列的實現在 PHP 中資料結構PHP
- 資料結構之php實現單向連結串列資料結構PHP
- 資料結構-連結串列資料結構
- 連結串列-資料結構資料結構
- 資料結構 - 連結串列資料結構
- 資料結構--連結串列資料結構
- 資料結構—連結串列資料結構
- 資料結構實驗之連結串列二:逆序建立連結串列資料結構
- 資料結構實驗之連結串列九:雙向連結串列資料結構
- 【資料結構】用C語言實現單連結串列及其常見操作資料結構C語言
- 資料結構實驗之連結串列三:連結串列的逆置資料結構
- 資料結構實驗之連結串列五:單連結串列的拆分資料結構
- 資料結構實驗之連結串列六:有序連結串列的建立資料結構
- 資料結構實驗之連結串列一:順序建立連結串列資料結構
- 用c語言實現資料結構——單連結串列C語言資料結構
- 資料結構-2.單向連結串列的實現資料結構
- 資料結構--單連結串列(通過陣列實現)資料結構陣列
- 資料結構——單連結串列介面實現(C語言)資料結構C語言
- 二叉連結串列儲存結構、二叉樹相關操作二叉樹
- 資料結構之「連結串列」資料結構
- JavaScript資料結構--連結串列JavaScript資料結構
- 資料結構之連結串列資料結構
- 資料結構實驗之連結串列四:有序連結串列的歸併資料結構
- 演算法與資料結構-連結串列((linked-list)-Java實現單向連結串列演算法資料結構Java
- 連結串列-單連結串列實現