1. 程式人生 > >資料結構中單鏈表的那些事

資料結構中單鏈表的那些事

在面試中面試資料結構中關於連結串列的基本操作,從未到頭列印單鏈表、逆置\翻轉單鏈表、合併兩個有序連結串列,合併後連結串列依然有序、查詢單鏈表的中間結點,只能遍歷一次單鏈表、刪除連結串列的倒數第K個結點,要求只能遍歷一次單鏈表等連結串列的操作,都是面試中常考題,所以這些是必須會的,實現如下

head.h

#pragma once
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>

typedef int DataType;

typedef struct ListNode
{
    struct ListNode* _pNext;
    DataType data;
}*PNode;



void PrintSListFromTail2Head(PNode pHead);                           // 逆序列印單鏈表 

void DeleteListNotTailNode(PNode pos);                               // 刪除連結串列的非尾結點,要求:不能遍歷連結串列 


void InesrtPosFront(PNode pos, DataType data);                      // 在連結串列pos位置前插入值到data的結點 


PNode FindMiddleNode(PNode pHead);                                  // 查詢連結串列的中間結點,要求只能遍歷一次連結串列 


PNode FindLastKNode(PNode pHead, int K);                            // 查詢連結串列的倒數第K個結點,要求只能遍歷一次連結串列


PNode DeleteLastKNode(PNode pHead, int K);                          // 刪除連結串列的倒數第K個結點,要求只能遍歷一次連結串列 


void JosephCircle(PNode* pHead, const int M);                       // 用單鏈表實現約瑟夫環 


void ReverseSList(PNode* pHead);                                    // 連結串列的逆置--三個指標 


PNode ReverseSListOP(PNode pHead);                                  // 連結串列的逆置--頭插法 


void BubbleSort(PNode pHead);                                        // 用氣泡排序思想對單鏈表進行排序 


PNode MergeSList(PNode pHead1, PNode pHead2);                       // 合併兩個有序單鏈表,合併後依然有序


int IsSListCross(PNode pHead1, PNode pHead2);                       // 判斷兩個單鏈表是否相交---連結串列不帶環 


PNode GetCorssNode(PNode pHead1, PNode pHead2);                     // 求兩個單鏈表相交的交點---連結串列不帶環 

head.c

#include"head.h"

void PrintSListFromTail2Head(PNode pHead)                           // 逆序列印單鏈表 
{   
    assert(pHead);
    PNode pNewNode = pHead;

    if (NULL == pHead)
    {
        return;
    }
    else if (pNewNode)
    {
        PrintSListFromTail2Head(pNewNode->_pNext);
    }
    printf("%d", pNewNode->data);
    return;
}

void DeleteListNotTailNode(PNode pos)                               // 刪除連結串列的非尾結點,要求:不能遍歷連結串列 
{
    PNode p_Cur = pos->_pNext;
    pos->data =p_Cur->data;
    pos->_pNext = p_Cur->_pNext;
    free(p_Cur);
    p_Cur = NULL;
}

void InesrtPosFront(PNode pos, DataType data)                       // 在連結串列pos位置前插入值到data的結點 
{
    PNode p = pos->_pNext;                     //放置pos位置後面的指標
    pos ->_pNext = (PNode)BuyNewNode(pos->data);      //新建立的結點放在pos後面,並且新建立的結點的data是pos位置的data
    pos->_pNext->_pNext = p;                   //將原來pos後面的結點連線起來
    pos->data = data;                          //將需要插入的資料元素放在pos的位置

}

PNode FindMiddleNode(PNode pHead)                                  // 查詢連結串列的中間結點,要求只能遍歷一次連結串列 
{
    assert(pHead);
    if (NULL == pHead->_pNext )
    {
        return pHead;
    }
    PNode Fast = pHead;                        //建立一個快指標,每次走兩步
    PNode Slow = pHead;                        //建立一個慢指標,一次走一步

    while (Fast && Fast->_pNext)               //判斷元素個數是奇數和偶數時,返回中間結點
    {
        Fast = Fast->_pNext->_pNext;
        Slow = Slow->_pNext;
    }
    return Slow;                               //最後返回慢指標剛好走到中間結點
}

PNode FindLastKNode(PNode pHead, int K)                            // 查詢連結串列的倒數第K個結點,要求只能遍歷一次連結串列
{
    assert(pHead);
    if (NULL == pHead || K<=0)                                 //判空連結串列和輸入的合法性
    {
        return NULL;
    }
    PNode Fast = pHead;
    PNode Slow = pHead;

    while (K--)
    {
        Fast = Fast->_pNext;                                  //快指標先向後走k步,然後慢指標和快指標一起以相同的速度向後走
    }

    while (Fast)
    {
        Fast = Fast->_pNext;
        Slow = Slow->_pNext;
    }
        return Slow;
}

PNode DeleteLastKNode(PNode pHead, int K)                          // 刪除連結串列的倒數第K個結點,要求只能遍歷一次連結串列 
{
    assert(pHead);
    if (NULL == pHead)
    {
        return NULL;
    }
    PNode Fast = pHead;
    PNode Slow = pHead;
    PNode Cur_Node = NULL;

    while (K--)
    {
        Fast = Fast->_pNext;                                  //快指標先向後走k步,然後慢指標和快指標一起以相同的速度向後走
    }

    while (Fast)
    {
        Fast = Fast->_pNext;
        Cur_Node = Slow;
        Slow = Slow->_pNext;
        Cur_Node->_pNext = Slow->_pNext;
    }
    return pHead;
}

void JosephCircle(PNode* pHead, const int M)                        // 用單鏈表實現約瑟夫環 
{
    PNode Cur_node = NULL;
    PNode Del_node = NULL;
    int count = 0;
    assert(pHead);
    if (NULL == pHead || M <= 0)
    { 
        return;
    }

    Cur_node = *pHead;
    while (Cur_node->_pNext)
    {
        Cur_node = Cur_node->_pNext;
    }
    Cur_node->_pNext = *pHead;
    Cur_node = *pHead;

    while (Cur_node->_pNext != Cur_node)
    {
        count = M;
        while (--count)
        {
            Cur_node = Cur_node->_pNext;
        }
        Del_node = Cur_node->_pNext;
        Cur_node->_pNext  = Del_node->_pNext;
        free(Del_node);
        Del_node = NULL;
    }

}

void ReverseSList(PNode* pHead)                                    // 連結串列的逆置--三個指標 
{
    PNode Pre_node = NULL;
    PNode Cur_node = NULL;
    PNode Next_node = NULL;
    assert(pHead);
    Cur_node = *pHead;
    while (Cur_node)
    {
        Pre_node = Cur_node;
        Cur_node = Cur_node->_pNext;
        Pre_node->_pNext = Next_node;
        Next_node = Pre_node;
    }
}   

PNode ReverseSListOP(PNode pHead)                                  // 連結串列的逆置--頭插法 
{
    PNode Cur_node = NULL;
    PNode Next_node = NULL;
    assert(pHead);
    if (NULL == pHead || NULL == pHead->_pNext)
    {
        return NULL;
    }

    while (pHead)
    {
        Cur_node = pHead;
        pHead = pHead->_pNext;
        Cur_node->_pNext = Next_node;
        Next_node = Cur_node;
    }
    pHead = Next_node;

    return pHead;
}



void BubbleSort(PNode pHead)                                        // 用氣泡排序思想對單鏈表進行排序,從小到大排序
{
    PNode Tail = NULL;
    PNode P_Cur = pHead;
    int flag = 0;

    if (NULL == pHead || NULL == pHead->_pNext)
    {
        return;
    }

    while (Tail != pHead)                   //先判斷單鏈表是否是有序的,按照排序結果,如果一趟排序,標記flag沒有發生變化就直接列印單鏈表
    {
        P_Cur = pHead;
        flag = 0;
    }

    while (P_Cur!=Tail)
    {
        while (P_Cur->_pNext!=Tail)
        {
            if (P_Cur->data > P_Cur->data)
        {
            DataType tmp = P_Cur->data;
            P_Cur->data = P_Cur->_pNext->data;
            P_Cur->_pNext->data = tmp;
            flag = 1;
        }
            P_Cur = P_Cur->_pNext;
        }
        Tail = P_Cur;

        if (0 == flag)
        {
            return;
        }

    }
}

PNode MergeSList(PNode pHead1, PNode pHead2)                       // 合併兩個有序單鏈表,合併後依然有序
{   
    PNode  P_NewNode = NULL;
    pHead1 = pHead1->_pNext;
    pHead2 = pHead2->_pNext;
    P_NewNode = pHead1;

    while (pHead1 && pHead2)                                    //兩個連結串列首先都不為空,然後判斷兩個連結串列的data的大小
    {
        if (pHead1->data > pHead2->data)
        {
            P_NewNode = P_NewNode->_pNext;
            P_NewNode->data  = pHead2->data;
            pHead2 = pHead2->_pNext;
        }
        else
        {
            P_NewNode = P_NewNode->_pNext;
            P_NewNode->data  = pHead1->data;
            pHead1 = pHead1->_pNext;
        }
    }
    P_NewNode->_pNext = pHead1 ? pHead1 : pHead2;         //判斷連結串列是否一個已經為空,直接將另一個連結串列的內容連結在後面
    free(pHead2);
    return P_NewNode;
}

int IsSListCross(PNode pHead1, PNode pHead2)                        // 判斷兩個單鏈表是否相交---連結串列不帶環 
{
    PNode p1 = pHead1;
    PNode p2 = pHead2;
    int p1_Size = 0;                   //pHead1的大小,設定計數器計數
    int p2_Size = 0;                   //pHead2的大小,設定計數器計數
    int k = 0;                         //PHead1和PHead大小比較相差的步數

    if (NULL == p1 || NULL == p2)                               //判斷連結串列是否為空,如果為空就返回0,所以不想交
    {                                    
        return 0;
    }

    while (p1)                                        //連結串列1不為空繼續計數
    {
        p1_Size++;
        p1 = p1->_pNext;
    }
        while (p2)                                       //連結串列的大小
    {
    p2_Size++;
    p2 = p2->_pNext;
}

if (p1_Size > p2_Size)
{
    k = p1_Size - p2_Size;
    while (k--)
    {
        p1->_pNext;
    }
    p2->_pNext;
    if (p1->data == p2->data)
    {
        return 1;
    }
}

if (p1_Size < p2_Size)
{
    k = p2_Size - p1_Size;
    while (k--)
    {
        p2->_pNext;
    }
    p1->_pNext;
}
if (p1->data == p2->data)
{
    return 1;
}

}

PNode GetCorssNode(PNode pHead1, PNode pHead2)                     // 求兩個單鏈表相交的交點---連結串列不帶環
{   
    PNode p1 = pHead1;
    PNode p2 = pHead2;
    int p1_Size = 0;                   //pHead1的大小,設定計數器計數
    int p2_Size = 0;                   //pHead2的大小,設定計數器計數
    int k = 0;                         //PHead1和PHead大小比較相差的步數

    if (NULL == p1 || NULL == p2)                               //判斷連結串列是否為空,如果為空就返回0,所以不想交
    {
        return NULL;
    }

    while (p1)                                        //連結串列1不為空繼續計數
    {
        p1_Size++;
        p1 = p1->_pNext;
    }
    while (p2)                                       //連結串列的大小
    {
        p2_Size++;
        p2 = p2->_pNext;
    }

    if (p1_Size > p2_Size)
    {
        k = p1_Size - p2_Size;
        while (k--)
        {
            p1->_pNext;
        }
        p2->_pNext;
        if (p1->data == p2->data)
        {
            return p1;
        }
    }

    if (p1_Size < p2_Size)
    {
        k = p2_Size - p1_Size;
        while (k--)
        {
            p2->_pNext;
        }
        p1->_pNext;
    }
    if (p1->data == p2->data)
    {
        return p1;
    }
    else
    {
        return NULL;
    }

}

相關推薦

資料結構單鏈那些

在面試中面試資料結構中關於連結串列的基本操作,從未到頭列印單鏈表、逆置\翻轉單鏈表、合併兩個有序連結串列,合併後連結串列依然有序、查詢單鏈表的中間結點,只能遍歷一次單鏈表、刪除連結串列的倒數第K個結點,要求只能遍歷一次單鏈表等連結串列的操作,都是面試中常考題,所

C 資料結構單鏈基本操作

C中的typedef C中的typedef關鍵字作用是為一種資料型別定義一個新名字,這樣做的目的有兩個,一是給變數定義一個易記且意義明確的新名字,如: typedef unsigned char BYTE; 把unsigned char型別自命名為BYTE。另一個目的是

資料結構單鏈的 頭插法和尾插法

正在學習資料結構中的連結串列,在有沒有頭節點的問題上的 頭插法跟尾插法一直模糊。。。。。 作為一個新手,整理了一下在有節點時的 頭插法跟尾插法 頭插法程式碼: int InsertHread(LinkList &L,int e) { LinkList tamp

資料結構單鏈的實現+單鏈的C語言實現原始碼

線性表(List):零個或多個數據元素的有限序列。線性表的抽象資料型別。 線性表的順序儲存: 優點:無須為表示表中元素的邏輯關係而額外的儲存空間,可以快速的取表中任意位置的元素。 缺點:插入和刪除操作需要轉移大量元素,線性表的長度較大時,難以確定儲存空間的容量, 造成儲存空

資料結構單鏈插入刪除操作

#include<iostream> using namespace std; typedef struct LNode { int data; struct LNode *next; }LNode; void createListR(LNode *C, int a[], int n

重學資料結構(一)單鏈

最近在重新學習資料結構,特此記錄學習過程,碼農再次上線 關於單鏈表的一些基本操作,以下為基本思路程式碼 首先看一張直觀圖 連結串列的結構體定義如下(為簡便,這裡的ElemType採用int): //單鏈表 typedef struct LNode {

C#資料結構單鏈(LinkList)例項詳解

本文例項講述了C#資料結構之單鏈表(LinkList)實現方法。分享給大家供大家參考,具體如下: 這裡我們來看下“單鏈表(LinkList)”。在上一篇《C#資料結構之順序表(SeqList)例項詳解》的最後,我們指出了:順序表要求開闢一組連續的記憶體空間,而且插入/刪除元素時,為了保證元素的順序

演算法與資料結構單鏈

分享一下我老師大神的人工智慧教程!零基礎,通俗易懂!http://blog.csdn.net/jiangjunshow 也歡迎大家轉載本篇文章。分享知識,造福人民,實現我們中華民族偉大復興!        

資料結構 線性,棧,佇列,演算法之間的聯絡與區別

一。連結串列為什麼需要         在程式中,經常需要將一種(通常是同為某個型別的)資料元素作為整體管理和使用,需要建立這種元素組,用變數記錄他們,傳進傳出函式等。一組元素可能發生變化(像增加或刪除元素。)      

資料結構單鏈的逆序輸出

即:將一個已經建立好的單鏈表進行指標域的改變 今天突然被問到單鏈表逆序的問題,弄了好久才看出別人的程式有啥問題,就重新寫了一遍。 今天才在CSDN客戶端上看到美團的面試題是氣泡排序。 一個看似簡單的問題難倒很多人,所以簡單的不要因為他簡單就忽視它,人們在簡單的問題上越容易犯錯!

資料結構回顧-------單鏈

單鏈表,用指標來實現的線性表 為了方便操作,我們定義一個頭指標來操作連結串列 結構體為Node      一個整型data,一個Node指標next指向下一個節點 封裝類為LinkList    連結串列的各個操作具體看類的函式即可。 /*

資料結構單鏈

從今天起開始資料結構系列的分享,今天分享的是單鏈表。單鏈表大概是大概是每個資料結構 初學者的必經之路,下面結合一個小小的工程深入學習單鏈表的使用–簡易客戶管理系統。 ps:如果還不清楚單鏈表是什麼的小夥伴自行百度,在此不在贅述 專案結構 如

初識資料結構單鏈——Java語言

import java.util.Scanner; public class LinkList{ ListNode H = new ListNode(0); /** *尾插法建立連結串列 */ public void creatLinkList(){ ListNode f

資料結構與演算法的那些

先佔坑,再補充。 常用演算法: (1)排序:快排、歸併排序、插入排序、希爾排序、桶排序; (2)分治演算法(divide-and-conquer),回溯演算法,貪婪演算法,動態規劃(DP); (3)二分查詢(binary search);   一、排序演算法 演

資料結構單鏈的實現

單鏈表是線性錶鏈式儲存的一種形式,其中的結點一般含有兩個域,一個是存放資料資訊的info域,另一個是指向該結點後繼結點存放地址的指標next域。一個單鏈表必須要有一個首指標指向連結串列中的第一個結點。 單鏈表要掌握以下幾種操作: 1、建立一個空的單鏈表。 2、輸出單鏈表

資料結構單鏈-----基本操作

刪除指定位置的節點 void Erase(pList * pplist, pNode pos) { assert(pplist != NULL); assert(pos != NULL); if (*pplist == pos)//如果指向第一個節點

資料結構單鏈的就地逆置

6-1 帶頭結點的單鏈表就地逆置(10 分)   本題要求編寫函式實現帶頭結點的單鏈線性表的就地逆置操作函式。L是一個帶頭結點的單鏈表,函式ListReverse_L(LinkList &L)要求在不新開闢節點的前提下將單鏈表中的元素進行逆置,如原單鏈表元素依次為1

資料結構單鏈(無頭單向非迴圈連結串列)各個介面的實現

順序表存在的問題: 中間/頭部的插入刪除,時間複雜度為O(N) 增容需要申請新空間,拷貝資料,釋放舊空間。會有不小的消耗 增容一般是呈2倍的增長,勢必會有一定的空間浪費。 例如當前容量為100,滿了以後增容到200,如果再繼續插入了5個數據,後面沒有資料插入了,

資料結構單鏈的運用 多項式加法

#include<stdio.h> #include<stdlib.h> struct mono{     int e;     int c; }; struct node{     mono data;     node * next; }; str

資料結構單鏈(二)

//判斷單鏈表是否有環:思路:設定兩個"指標",一個走一步,一個走兩步,若存在環,則一定會存在有相交的位置點 public boolean isLoop(Linklist LNode){ Node p=head.next; Node q=h