• 双链表排序 双链表 (Doubly Linked List) Doubly linked list is a type of linked list in which each node apart from storing its data has two links. The first link points to the previous node in the list...

双链表排序
Doubly linked list is a type of linked list in which each node apart from storing its data has two links. The first link points to the previous node in the list and the second link points to the next node in the list. The first node of the list has its previous link pointing to NULL similarly the last node of the list has its next node pointing to NULL.
双链表是一种链表，其中每个节点(除存储其数据外)都有两个链接。 第一个链接指向列表中的上一个节点，第二个链接指向列表中的下一个节点。 列表的第一个节点的上一个链接指向NULL，类似地，列表的最后一个节点的下一个节点指向NULL。

The two links help us to traverse the list in both backward and forward direction. But storing an extra link requires some extra space.
这两个链接可帮助我们在向前和向后的方向上遍历列表。 但是存储额外的链接需要一些额外的空间。
双链表的实现 (Implementation of Doubly Linked List)
First we define the node.
首先，我们定义节点。
struct node
{
int data;     	// Data
node *prev;  	// A reference to the previous node
node *next; 	// A reference to the next node
};
Now we define our class Doubly Linked List. It has the following methods:
现在，我们定义类“双重链接列表”。 它具有以下方法：
class Doubly_Linked_List
{
node *front;  	// points to first node of list
node *end;   	// points to first las of list
public:
{
front = NULL;
end = NULL;
}
void delete_node(node*);
void forward_traverse();
void backward_traverse();
};
在开头插入数据 (Insert Data in the beginning)
The prev pointer of first node will always be NULL and next will point to front.  第一节点的分组指针将始终是NULL和下一个将指向前方 。 If the node is inserted is the first node of the list then we make front and end point to this node. 如果插入的节点是列表的第一个节点，则我们将前端和终点指向该节点。 Else we only make front point to this node. 否则，我们仅将前端指向该节点。

void Doubly_Linked_List :: add_front(int d)
{
// Creating new node
node *temp;
temp = new node();
temp->data = d;
temp->prev = NULL;
temp->next = front;

// List is empty
if(front == NULL)
end = temp;

else
front->prev = temp;

front = temp;
}
在节点之前插入数据 (Insert Data before a Node)
Let’s say we are inserting node X before Y. Then X’s next pointer will point to Y and X’s prev pointer will point the node Y’s prev pointer is pointing. And Y’s prev pointer will now point to X. We need to make sure that if Y is the first node of list then after adding X we make front point to X.
假设我们在Y之前插入节点X。然后X的下一个指针将指向Y，X的prev指针将指向节点Y的prev指针指向。 Y的prev指针现在将指向X。我们需要确保，如果Y是列表的第一个节点，那么在添加X之后，我们将指向X的前端。

void Doubly_Linked_List :: add_before(node *n, int d)
{
node *temp;
temp = new node();
temp->data = d;
temp->next = n;
temp->prev = n->prev;
n->prev = temp;

//if node is to be inserted before first node
if(n->prev == NULL)
front = temp;
}
在节点之后插入数据 (Insert Data after a Node)
Let’s say we are inserting node Y after X. Then Y’s prev pointer will point to X and Y’s next pointer will point the node X’s next pointer is pointing. And X’s next pointer will now point to Y. We need to make sure that if X is the last node of list then after adding Y we make end point to Y.
假设我们在X之后插入节点Y。然后，Y的上一个指针将指向X，Y的下一个指针将指向节点X的下一个指针指向。 X的下一个指针现在将指向Y。我们需要确保，如果X是列表的最后一个节点，那么在添加Y之后，我们将端点指向Y。
void Doubly_Linked_List :: add_after(node *n, int d)
{
node *temp;
temp = new node();
temp->data = d;
temp->prev = n;
temp->next = n->next;
n->next = temp;

//if node is to be inserted after last node
if(n->next == NULL)
end = temp;
}
最后插入数据 (Insert Data in the end)
The next pointer of last node will always be NULL and prev will point to end.  最后一个节点的下指针将始终为NULL和prev将指向结束。 If the node is inserted is the first node of the list then we make front and end point to this node. 如果插入的节点是列表的第一个节点，则我们将前端和终点指向该节点。 Else we only make end point to this node. 否则，我们仅将端点指向此节点。

void Doubly_Linked_List :: add_end(int d)
{
// create new node
node *temp;
temp = new node();
temp->data = d;
temp->prev = end;
temp->next = NULL;

// if list is empty
if(end == NULL)
front = temp;
else
end->next = temp;
end = temp;
}
删除节点 (Remove a Node)
Removal of a node is quite easy in Doubly linked list but requires special handling if the node to be deleted is first or last element of the list. Unlike singly linked list where we require the previous node, here only the node to be deleted is needed. We simply make the next of the previous node point to next of current node (node to be deleted) and prev of next node point to prev of current node. Look code for more details.
在双向链接列表中，删除节点非常容易，但是如果要删除的节点是列表的第一个或最后一个元素，则需要特殊处理。 与我们需要上一个节点的单链表不同，这里仅需要删除的节点。 我们只需使上一个节点的下一个指向当前节点的下一个(要删除的节点)，然后使下一个节点的prev指向当前节点的上一个。 查看代码以获取更多详细信息。

void Doubly_Linked_List :: delete_node(node *n)
{
// if node to be deleted is first node of list
if(n->prev == NULL)
{
front = n->next; //the next node will be front of list
front->prev = NULL;
}
// if node to be deleted is last node of list
else if(n->next == NULL)
{
end = n->prev;   // the previous node will be last of list
end->next = NULL;
}
else
{
//previous node's next will point to current node's next
n->prev->next = n->next;
//next node's prev will point to current node's prev
n->next->prev = n->prev;
}
//delete node
delete(n);
}
向前遍历 (Forward Traversal)
Start with the front node and visit all the nodes untill the node becomes NULL.
从前端节点开始并访问所有节点，直到该节点变为NULL。
void Doubly_Linked_List :: forward_traverse()
{
node *trav;
trav = front;
while(trav != NULL)
{
cout<<trav->data<<endl;
trav = trav->next;
}
}
向后遍历 (Backward Traversal)
Start with the end node and visit all the nodes until the node becomes NULL.
从结束节点开始，并访问所有节点，直到该节点变为NULL。
void Doubly_Linked_List :: backward_traverse()
{
node *trav;
trav = end;
while(trav != NULL)
{
cout<<trav->data<<endl;
trav = trav->prev;
}
}

双链表排序

展开全文
• ## 双向链表排序

万次阅读 2018-07-17 20:52:18
双向链表的结构体，包括一个前驱节点的指针、一个后继节点的指针以及一个存储数据的data域，initList函数初始化单节点的双链表，addList函数采用头插入方法添加一个节点到双链表中，sort函数实现了对双链表的排序，采用头插入方式建成的双链表的头结点（存储65535的那个节点）必然在末尾（其实双链表没有首尾之说，只是把它当作末尾），排序的时候，1.首先从该节点处，每次查找前驱节点，并记录data获取链表中data最大的节点，并记录指向这个节点的指针和其值。2.将此节点采用头插入的方式插入到链表中（注意要先删除这个节点在链表中的位置）3.再次从头节点处，通过前驱节点遍历整个链表（此时要去掉第一次找到的最大值）找到最大值。
typedef struct node{     int data;     struct node *prior,*next; }Link;

int max;
max = tmp->data;
flag = tmp;
p = tmp->prior;
while(p->data != 65535){//找到值最大的节点并且标记
if(p->data > max){
max = p->data;
flag = p;
flag->data = max;
}
p = p->prior;
}
{//交换最大值点到头节点后
flag->prior->next = flag->next;
flag->next->prior = flag->prior;
}
p = tmp->prior;   //从后往前寻找
while(p->data != flag->data){//找到要交换的节点
if(p->data > tmp->data){
tmp = p;
}
p = p->prior;
}
{//交换两个节点
tmp->prior->next = tmp->next;
tmp->next->prior = tmp->prior;
}
}
}
主函数的调用代码就比较简单了。
int i;
int a[15]={7,4,2,7,5,8,6,3,2,4,5,7,98,3,4};
for(i=0;i<15;i++){
}
while(p->data!=65535){
printf("%d<-->",p->data);
p = p->next;
}
printf("\n");
while(p->data!=65535){
printf("%d<-->",p->data);
p = p->next;
}
printf("\n");     getchar(); }
展开全文
• 双链表实现链表的合并以及链表的排序，其中包括链表的一些基本操作也有用于链表排序，链表合并的函数
• C语言 链表排序,源代码，代码清晰，适合初学者下载
• 双向链表也叫双链表，是链表的一种，它的每个数据结点中都有两个指针，分别指向直接后继和直接前驱。所以，从双向链表中的任意一个结点开始，都可以很方便地访问它的前驱结点和后继结点。 链表中的每个节点的成员...
1. 双向链表的定义

【百度百科】
双向链表也叫双链表，是链表的一种，它的每个数据结点中都有两个指针，分别指向直接后继和直接前驱。所以，从双向链表中的任意一个结点开始，都可以很方便地访问它的前驱结点和后继结点。
链表中的每个节点的成员由两部分组成： 1. 数据域：专门用来保存各个成员的信息数据。 2. 指针域：专门用来与其他节点链接。

2. 结构体中的两个重要指针

直接后继 & 直接前驱：
直接后继：我个人习惯称之为后向指针，也习惯定义为pnext,该指针指向下一个节点，如果该节点为尾节点，那么pnext指向NULL。  直接前驱：同样我习惯称之为后向指针，也习惯定义为prev,该指针指向前一个节点，如果该节点为头节点，那么prev指向NULL。

3. 双向链表中节点的成员排序(冒泡排序)

在排序之前我们需要明确一点：<明确我们操作的链表的头节点的数据域是否写有数据>
因为有时候程序员写代码时为了链表方便操作会专门创建一个表头(头结点)，即不存放数据的表头。

3.1头节点数据域为空
接下来我们来看几段代码：
typedef struct student
{
int num;
char name[20];
float score;
struct student *prev;
struct student *pnext;
}STU,*PSTU;
//1.首先我们定义一个结构体，有数据域(前三个)和指针域(后两个)两部分
//2.将结构体和结构体指针分别重命名为STU,PSTU

冒泡排序代码如下：
#incldue <stdio.h>

{
int i=0,j=0;

   //****冒泡排序****//
for(i=0;i<n;i++)
{
pn=p->pnext;
for(j=0;j<n-1-i;j++)
{
if(p->score < pn->score)          //判断，条件成立之后交换位置
{
if(pn->pnext==NULL)           //判断是否为尾节点
{
//**交换位置代码**//
p->pnext=pn->pnext;
pn->prev=p->prev;
pn->pnext=p;
p->prev->pnext=pn;
p->prev=pn;
//**位置交换结束**//
}
else
{
//**交换位置代码**//
p->pnext=pn->pnext;
pn->prev=p->prev;
pn->pnext=p;
p->prev->pnext=pn;
//下一行请注意//
pn->pnext->prev=p;
p->prev=pn;
//**位置交换结束**//
pn=p->pnext;      //位置交换结束之后进行指针偏移，pn指向p的下一个节点
}
else                                       //条件不成立
{
p=p->pnext;
pn=p->pnext;
//如果未发生位置交换，则两个指针都要发生偏移
}
}
}
}

重点： 在上一段代码中一定要注意我在代码前面注释的那一行，并且要与不是尾结点的情况对比来看，你会发现少了一行代码， pn->pnext->prev=p,我先解释一下这一行代码是什么意思，从上面的代码可以看出两个临时指针的位置关系为p总是在Pn的前面，那也就是说满足交换位置条件之后进行位置交换，交换之后两个临时指针位置就随之交换，在交换的过程中，假如有尾结点，那么pn的后向指针指向NULL，随之 pn->pnext->prev 就会出现段错误。

3.2头节点数据域不为空(一般不建议)
这种方式在数据处理上面会比较麻烦，一旦头结点的数据发生位置交换(比如排序，插入结点，删除结点等)，那么在函数的封装是就要考虑将新的头结点返回。

接下来我们来看几段代码：
typedef struct student
{
int num;
char name[20];
float score;
struct student *prev;
struct student *pnext;
}STU,*PSTU;
//1.首先我们定义一个结构体，有数据域(前三个)和指针域(后两个)两部分
//2.将结构体和结构体指针分别重命名为STU,PSTU

冒泡排序部分核心代码如下：
#incldue <stdio.h>

{
int i=0,j=0;

   //****冒泡排序****//
for(i=0;i<n;i++)
{
pn=p->pnext;
for(j=0;j<n-1-i;j++)
{
if(p->score < pn->score)          //判断，条件成立之后交换位置
{
if(j==0）//***重点参考                //判断头结点是否会参与位置交换
{
p->pnext=p1->pnext;
p1->prev=p->prev;
p1->pnext=p;
p1->pnext->prev=p;
p->prev=p1;

p1=p->pnext;
}
......//中间省略部分代码//......
else
{
//**交换位置代码**//
p->pnext=pn->pnext;
pn->prev=p->prev;
pn->pnext=p;
p->prev->pnext=pn;
//下一行请注意//
pn->pnext->prev=p;
p->prev=pn;
//**位置交换结束**//
pn=p->pnext;         //位置交换结束之后进行指针偏移，pn指向p的下一个节点
}
else                                       //条件不成立
{
p=p->pnext;
pn=p->pnext;
//如果未发生位置交换，则两个指针都要发生偏移
}
}
}
}

重点： 在看上面的代码时我们需要与3.1节的内容对比来看，因为3.2节的中要单独考虑的情况有四种：
头结点发生改变： 重点要考虑头指针的的前向指针为NULL；尾结点发生改变： 重点要考虑尾结点的的后向向指针为NULL；有且仅有两个结点(即头结点和尾结点)： 重点要考虑头指针的的前向指针为NULL且尾结点的的后向向指针为NULL；发生位置交换的结点不包含头结点和尾结点： 这种情况下交换位置的6行代码都不能少；
以上就是就是本次的所有内容，朋友如若发现问题，随时欢迎交流，希望能帮到你！！！
展开全文
• 【C语言】双链表的实现与冒泡排序 基于C语言，不做标题党，LInux下GCC通过编译，大致流程（底部附图，源码）： 新建双链表（节点数自定义），对节点data域用随机数种子进行随机赋值，并对该链表进行冒泡排序。 ...
【C语言】双链表的实现与冒泡排序
基于C语言，不做标题党，LInux下GCC通过编译，大致流程（底部附图，源码）：
	新建双链表（节点数自定义），对节点data域用随机数种子进行随机赋值，并对该链表进行冒泡排序。
后续其他排序陆续更新......

全局自定义函数如下：
	//链表新建函数

//创建101个结点

//链表data域赋值

//遍历

//链表长度（包含头结点）

//交换节点

//冒泡排序

具体代码如下：
#include <time.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX 100

//创建一个双链表结点
int data;            //数据域
};

//链表新建函数
//新结点分配内存

//判断内存分配成功失败
if (Node == NULL) {
printf("Memory distribution fail!\n");
return NULL;
}

//指针域初始化
Node->pre = NULL;
Node->next = NULL;

return Node;
}

//创建101个结点
//判空
return;

//首个带有数据的节点开辟空间

int num = MAX - 1;        //（100 - 1 + 2）= 101

while (num) {
//pCurrent->next开辟空间（带有衔接next指针作用）

//记录pCurrent，便于回滚

//双链表pre指针衔接
pCurrent->next->pre = pCurrent;

//回滚
pCurrent = pCurrent->next;

//计数
num--;
}

//置空末指针
pCurrent->next = NULL;

}

//链表data域赋值

//判空
return;

//辅助指针

//添加随机数种子
srand((unsigned) time(NULL));

//首个非空结点赋值
pCurrent->data = rand() % 500;

while (pCurrent) {
//随机赋值500以内整数值
pCurrent->data = rand() % 300;

//后移
pCurrent = pCurrent->next;

}
}

//遍历
//判空
return;

//辅助

//向前遍历指针

int num1 = 0;
//循环遍历
printf("———————————————————————————————————正遍历—————————————————————————————————————\n");

while (pCurrent) {
//print格式
//printf("%p\t",pCurrent);
printf("%d\t", pCurrent->data);

//向前遍历指针
temp = pCurrent;
num1++;

if (num1 % 10 == 0)
printf("\n");
//向后
pCurrent = pCurrent->next;

}

//向前遍历（尾节点开始）
pCurrent = temp;

int num2 = 0;

printf("————————————————————————————————————逆遍历————————————————————————————————————\n");
while (pCurrent) {
break;

printf("%d\t", pCurrent->data);

num2++;

if (num2 % 10 == 0)
printf("\n");

//向前
pCurrent = pCurrent->pre;

}
printf("————————————————————————————————————END————————————————————————————————————\n");

}

//链表长度（包含头结点）
//辅助

//计数
int size = 0;

while (pCurrent) {
//向后
pCurrent = pCurrent->next;

size++;
}

return size;
}

//交换节点

//指针转换	此处注意6个指针交换
//pPre与新前驱建立联系
pPre->pre->next = pCurrent;
pCurrent->pre = pPre->pre;

//pCurrent与新后驱建立联系
pCurrent->next->pre = pPre;
pPre->next = pCurrent->next;

//pPre与pCurrent互连
pPre->pre = pCurrent;
pCurrent->next = pPre;

}
/******************************排序开始******************************/

//冒泡排序
//判空
return;
}

//初始化辅助指针

//循环次数
int num = size;

for (int i = 1; i < num; i++) {

//重置指针位置
pCurrent = pPre->next;

for (int j = 1; j < num - i; j++) {
if (pPre->data > pCurrent->data) {

//节点尾节点情况
if (pCurrent->next == NULL) {
pPre->next = pCurrent->next;
pCurrent->pre = pPre->pre;
pCurrent->next = pPre;
pPre->pre->next = pCurrent;
pPre->pre = pCurrent;
}
//非尾节点情况
else {
//交换节点

//pCurrent指针后移到pPre前面
pCurrent = pPre->next;
}
}

//pPre->data > pCurrent->data非真情况下
else {
pPre = pPre->next;
pCurrent = pCurrent->next;
}
}
}
}

int main(void) {

//新建链表

//链表初始化

//链表data域赋值

//遍历

//冒泡

//交换结点

//遍历

return 0;
}


节点转换图：  运行效果图（第一次正逆遍历是初始化后的，第二次是排序后的）：  -------------------------------------------------------END-------------------------------------------------------
展开全文
• 打印链表函数PrintLinkedList 和 排序函数SortLinkedList 注：下面代码中的链表每项都是double类型，如果换做其他的类型或结构，则需要适当修改 /// /// 打印链表各结点信息 /// /// <param name=ll></param> ...
• 双向链表的访问，双向链表排序 题目 已知不带头结点的双向链表第一个节点的指针为list，链节点除了数据域和分别指向该结点的前驱结点和后继结点的指针域外，还设置记录该节点访问次数频度域freq(初始值为0)，请...
• 插入排序需要从后往前遍历寻找可以插入的位置，所以会使用到双向...创建带头节点的双链表 List create_list() { List head = (List)malloc(Size);//#define Size sizeof(struct Node) List p, q = head; if (head
• C语言，linux内核双链表实现快速排序，主要涉及到内核链表的基础操作，基地址转换和内核链表两个任意结点互换的实现。
• 链表排序相对数组的排序更为复杂些，也是考察求职者是否真正理解了排序算法（而不是“死记硬背”） 链表的插入排序 public class LinkedInsertSort { static class ListNode { int val; ListNode next; ...
• 方法一： 双链表的指针较为复杂，如果数据域部分较为简单，则直接对数据域进行交换即可。 void dLinkList::nameSort() { if(isEmpty()) cout空链表！\n"; else if(length()==1) cout*first; else { Student...
• #include &.../*双链表的定义：*/typedef char DataType;typedef struct dlistnode /*结点类型定义*/{ DataType data; struct dlistnode *prior,*next;}DListNode;typedef DListNode *DLinkL...
• 文章目录链表排序与数组排序的区别借助外部空间冒泡排序插入排序归并排序快速排序 链表排序与数组排序的区别 数组的排序几乎所有人都很熟悉了，常用的算法插入、冒泡、归并以及快排等都会或多或少依赖于数组可以在O...
• 双向链表循环的快速排序调用函数 #include #include #include #define T 1 #define F -1 typedef int bo; typedef char Type; struct Address { struct Address* next;
• 本文主要涵盖列表(双向链表)的设计及其排序算法的总结。列表是一种典型的动态存储结构。其中的数据，分散为一系列称作节点(node)的单位，节点之间通过指针相互索引和访问。为了引入新节点或删除原有节点，只需在局部...
• 题目：输入一棵二叉搜索树，将该二叉搜索树转换成一个排序的双向链表。 要求不能创建任何新的结点，只能调整树中结点指针的指向。 ''' class BinaryTreeNode(): def __init__(self, value, left = None, right = ...
• 以内核链表为例，进行冒泡排序
• 方法二改变指针指向归并排序分为两个部分: MergeSort 和 MergeMergeSort 是一个递归函数，在这个函数里面把待排序的数组或链表分段，直到每段的长度为1为止。Merge 在这个函数中把分开的两段结合起来，并且在结合的...
• 一种支持类模版和函数模版的C++双向链表，实现了各种排序算法（排序原则可定制），包含学生信息的使用示例(VC 6.0、VS2008).
• 前日遇到一个问题：对双向链表按关键字域进行排序。  在网上找了一下，都只一种算法，而且...于是自己想了一下，写了个带头结点的双向链表的选择排序算法，指针的交换浓缩到4种情况，而且自认为选择排序函数中的结
• 链表不仅作为链式存储的一种实现方式，还表达了计算机不连续（离散）的存储思想。
• ## 链表的排序

千次阅读 多人点赞 2019-01-07 10:32:11
链表排序 一、顺序表的排序 对顺序表的排序其实就是对结构体中的关键字的排序。 c语言版： 自定义结构体： typedef struct node { int age; int height; int width; }Node; 现在想根据其中的age...
• //冒泡排序 void BubbleSort(Node *pHead,Node *pTail){    int count = SizeList(pHead, pTail);  Node *pMove;  pMove = pHead->next;    while (count > 1) {  while (pMov
• ## 双链表的插入排序

千次阅读 2012-12-10 12:05:50
// 标识 ptr 每次排序后返回的...呃..的“故乡”。  mylist->Tail->next = NULL;  ptr->pre = NULL; // 先让 Tail 和 ptr 分手！！！  while (ptr)  {  if (mylist->Tail->data < ptr->data &&...
• 以Linux内核链表为例，进行选择排序
• helper函数的定义：以root为根节点的BST构造一个双向链表，并将新链表链接到state.prev节点上去，同时记录头节点和最后访问的节点的信息。 问题2：在问题1的基础上，每往链表中添加一个新节点，将头节点的prev指针...
• 前两篇博文，我讨论了链表的冒泡排序和选择排序（以Linux内核链表为例），这篇文章，我想说说插入排序
• ## 实现双链表的排序

千次阅读 2012-09-07 20:32:28
实现双链表排序： 方法一： 就是不变动节点，只把节点中数据进行交换。 采用选择排序法：   #include using namespace std; typedef struct DouLinkNode { int data ; struct DouLinkNode *pre ,*...
• 这两天关于双向链表的节点的交换,用了很长的时间去学习,理解,敲了好多次,总是达不到效果,就是能想明白,但是在写的时候不是出现这样就是那样的问题,最后参照另外一位CSDN博主的帖子,才写出一个完整的函数, ...

...